DeepCover Embedded Security in IoT: Public-key Secured Data Paths
Dependencies: MaximInterface
schema.h
00001 // Tencent is pleased to support the open source community by making RapidJSON available-> 00002 // 00003 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> 00004 // 00005 // Licensed under the MIT License (the "License"); you may not use this file except 00006 // in compliance with the License-> You may obtain a copy of the License at 00007 // 00008 // http://opensource->org/licenses/MIT 00009 // 00010 // Unless required by applicable law or agreed to in writing, software distributed 00011 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 00012 // CONDITIONS OF ANY KIND, either express or implied-> See the License for the 00013 // specific language governing permissions and limitations under the License-> 00014 00015 #ifndef RAPIDJSON_SCHEMA_H_ 00016 #define RAPIDJSON_SCHEMA_H_ 00017 00018 #include "document.h " 00019 #include "pointer.h" 00020 #include <cmath> // abs, floor 00021 00022 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) 00023 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 00024 #else 00025 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 00026 #endif 00027 00028 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) 00029 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1 00030 #else 00031 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0 00032 #endif 00033 00034 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX 00035 #include "internal/regex.h" 00036 #elif RAPIDJSON_SCHEMA_USE_STDREGEX 00037 #include <regex> 00038 #endif 00039 00040 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX 00041 #define RAPIDJSON_SCHEMA_HAS_REGEX 1 00042 #else 00043 #define RAPIDJSON_SCHEMA_HAS_REGEX 0 00044 #endif 00045 00046 #ifndef RAPIDJSON_SCHEMA_VERBOSE 00047 #define RAPIDJSON_SCHEMA_VERBOSE 0 00048 #endif 00049 00050 #if RAPIDJSON_SCHEMA_VERBOSE 00051 #include "stringbuffer.h" 00052 #endif 00053 00054 RAPIDJSON_DIAG_PUSH 00055 00056 #if defined(__GNUC__) 00057 RAPIDJSON_DIAG_OFF(effc++) 00058 #endif 00059 00060 #ifdef __clang__ 00061 RAPIDJSON_DIAG_OFF(weak-vtables) 00062 RAPIDJSON_DIAG_OFF(exit-time-destructors) 00063 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) 00064 RAPIDJSON_DIAG_OFF(variadic-macros) 00065 #endif 00066 00067 #ifdef _MSC_VER 00068 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated 00069 #endif 00070 00071 RAPIDJSON_NAMESPACE_BEGIN 00072 00073 /////////////////////////////////////////////////////////////////////////////// 00074 // Verbose Utilities 00075 00076 #if RAPIDJSON_SCHEMA_VERBOSE 00077 00078 namespace internal { 00079 00080 inline void PrintInvalidKeyword(const char* keyword) { 00081 printf("Fail keyword: %s\n", keyword); 00082 } 00083 00084 inline void PrintInvalidKeyword(const wchar_t* keyword) { 00085 wprintf(L"Fail keyword: %ls\n", keyword); 00086 } 00087 00088 inline void PrintInvalidDocument(const char* document) { 00089 printf("Fail document: %s\n\n", document); 00090 } 00091 00092 inline void PrintInvalidDocument(const wchar_t* document) { 00093 wprintf(L"Fail document: %ls\n\n", document); 00094 } 00095 00096 inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { 00097 printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); 00098 } 00099 00100 inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { 00101 wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); 00102 } 00103 00104 } // namespace internal 00105 00106 #endif // RAPIDJSON_SCHEMA_VERBOSE 00107 00108 /////////////////////////////////////////////////////////////////////////////// 00109 // RAPIDJSON_INVALID_KEYWORD_RETURN 00110 00111 #if RAPIDJSON_SCHEMA_VERBOSE 00112 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) 00113 #else 00114 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) 00115 #endif 00116 00117 #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ 00118 RAPIDJSON_MULTILINEMACRO_BEGIN\ 00119 context.invalidKeyword = keyword.GetString();\ 00120 RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ 00121 return false;\ 00122 RAPIDJSON_MULTILINEMACRO_END 00123 00124 /////////////////////////////////////////////////////////////////////////////// 00125 // Forward declarations 00126 00127 template <typename ValueType, typename Allocator> 00128 class GenericSchemaDocument; 00129 00130 namespace internal { 00131 00132 template <typename SchemaDocumentType> 00133 class Schema; 00134 00135 /////////////////////////////////////////////////////////////////////////////// 00136 // ISchemaValidator 00137 00138 class ISchemaValidator { 00139 public: 00140 virtual ~ISchemaValidator() {} 00141 virtual bool IsValid() const = 0; 00142 }; 00143 00144 /////////////////////////////////////////////////////////////////////////////// 00145 // ISchemaStateFactory 00146 00147 template <typename SchemaType> 00148 class ISchemaStateFactory { 00149 public: 00150 virtual ~ISchemaStateFactory() {} 00151 virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; 00152 virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; 00153 virtual void* CreateHasher() = 0; 00154 virtual uint64_t GetHashCode(void* hasher) = 0; 00155 virtual void DestroryHasher(void* hasher) = 0; 00156 virtual void* MallocState(size_t size) = 0; 00157 virtual void FreeState(void* p) = 0; 00158 }; 00159 00160 /////////////////////////////////////////////////////////////////////////////// 00161 // Hasher 00162 00163 // For comparison of compound value 00164 template<typename Encoding, typename Allocator> 00165 class Hasher { 00166 public: 00167 typedef typename Encoding::Ch Ch; 00168 00169 Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} 00170 00171 bool Null() { return WriteType(kNullType); } 00172 bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } 00173 bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); } 00174 bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); } 00175 bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); } 00176 bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); } 00177 bool Double(double d) { 00178 Number n; 00179 if (d < 0) n.u.i = static_cast<int64_t>(d); 00180 else n.u.u = static_cast<uint64_t>(d); 00181 n.d = d; 00182 return WriteNumber(n); 00183 } 00184 00185 bool RawNumber(const Ch* str, SizeType len, bool) { 00186 WriteBuffer(kNumberType, str, len * sizeof(Ch)); 00187 return true; 00188 } 00189 00190 bool String(const Ch* str, SizeType len, bool) { 00191 WriteBuffer(kStringType, str, len * sizeof(Ch)); 00192 return true; 00193 } 00194 00195 bool StartObject() { return true; } 00196 bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } 00197 bool EndObject(SizeType memberCount) { 00198 uint64_t h = Hash(0, kObjectType); 00199 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2); 00200 for (SizeType i = 0; i < memberCount; i++) 00201 h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive 00202 *stack_.template Push<uint64_t>() = h; 00203 return true; 00204 } 00205 00206 bool StartArray() { return true; } 00207 bool EndArray(SizeType elementCount) { 00208 uint64_t h = Hash(0, kArrayType); 00209 uint64_t* e = stack_.template Pop<uint64_t>(elementCount); 00210 for (SizeType i = 0; i < elementCount; i++) 00211 h = Hash(h, e[i]); // Use hash to achieve element order sensitive 00212 *stack_.template Push<uint64_t>() = h; 00213 return true; 00214 } 00215 00216 bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } 00217 00218 uint64_t GetHashCode() const { 00219 RAPIDJSON_ASSERT(IsValid()); 00220 return *stack_.template Top<uint64_t>(); 00221 } 00222 00223 private: 00224 static const size_t kDefaultSize = 256; 00225 struct Number { 00226 union U { 00227 uint64_t u; 00228 int64_t i; 00229 }u; 00230 double d; 00231 }; 00232 00233 bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } 00234 00235 bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } 00236 00237 bool WriteBuffer(Type type, const void* data, size_t len) { 00238 // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ 00239 uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); 00240 const unsigned char* d = static_cast<const unsigned char*>(data); 00241 for (size_t i = 0; i < len; i++) 00242 h = Hash(h, d[i]); 00243 *stack_.template Push<uint64_t>() = h; 00244 return true; 00245 } 00246 00247 static uint64_t Hash(uint64_t h, uint64_t d) { 00248 static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); 00249 h ^= d; 00250 h *= kPrime; 00251 return h; 00252 } 00253 00254 Stack<Allocator> stack_; 00255 }; 00256 00257 /////////////////////////////////////////////////////////////////////////////// 00258 // SchemaValidationContext 00259 00260 template <typename SchemaDocumentType> 00261 struct SchemaValidationContext { 00262 typedef Schema<SchemaDocumentType> SchemaType; 00263 typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType; 00264 typedef typename SchemaType::ValueType ValueType; 00265 typedef typename ValueType::Ch Ch; 00266 00267 enum PatternValidatorType { 00268 kPatternValidatorOnly, 00269 kPatternValidatorWithProperty, 00270 kPatternValidatorWithAdditionalProperty 00271 }; 00272 00273 SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) : 00274 factory(f), 00275 schema(s), 00276 valueSchema(), 00277 invalidKeyword(), 00278 hasher(), 00279 arrayElementHashCodes(), 00280 validators(), 00281 validatorCount(), 00282 patternPropertiesValidators(), 00283 patternPropertiesValidatorCount(), 00284 patternPropertiesSchemas(), 00285 patternPropertiesSchemaCount(), 00286 valuePatternValidatorType(kPatternValidatorOnly), 00287 propertyExist(), 00288 inArray(false), 00289 valueUniqueness(false), 00290 arrayUniqueness(false) 00291 { 00292 } 00293 00294 ~SchemaValidationContext() { 00295 if (hasher) 00296 factory.DestroryHasher(hasher); 00297 if (validators) { 00298 for (SizeType i = 0; i < validatorCount; i++) 00299 factory.DestroySchemaValidator(validators[i]); 00300 factory.FreeState(validators); 00301 } 00302 if (patternPropertiesValidators) { 00303 for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) 00304 factory.DestroySchemaValidator(patternPropertiesValidators[i]); 00305 factory.FreeState(patternPropertiesValidators); 00306 } 00307 if (patternPropertiesSchemas) 00308 factory.FreeState(patternPropertiesSchemas); 00309 if (propertyExist) 00310 factory.FreeState(propertyExist); 00311 } 00312 00313 SchemaValidatorFactoryType& factory; 00314 const SchemaType* schema; 00315 const SchemaType* valueSchema; 00316 const Ch* invalidKeyword; 00317 void* hasher; // Only validator access 00318 void* arrayElementHashCodes; // Only validator access this 00319 ISchemaValidator** validators; 00320 SizeType validatorCount; 00321 ISchemaValidator** patternPropertiesValidators; 00322 SizeType patternPropertiesValidatorCount; 00323 const SchemaType** patternPropertiesSchemas; 00324 SizeType patternPropertiesSchemaCount; 00325 PatternValidatorType valuePatternValidatorType; 00326 PatternValidatorType objectPatternValidatorType; 00327 SizeType arrayElementIndex; 00328 bool* propertyExist; 00329 bool inArray; 00330 bool valueUniqueness; 00331 bool arrayUniqueness; 00332 }; 00333 00334 /////////////////////////////////////////////////////////////////////////////// 00335 // Schema 00336 00337 template <typename SchemaDocumentType> 00338 class Schema { 00339 public: 00340 typedef typename SchemaDocumentType::ValueType ValueType; 00341 typedef typename SchemaDocumentType::AllocatorType AllocatorType; 00342 typedef typename SchemaDocumentType::PointerType PointerType; 00343 typedef typename ValueType::EncodingType EncodingType; 00344 typedef typename EncodingType::Ch Ch; 00345 typedef SchemaValidationContext<SchemaDocumentType> Context; 00346 typedef Schema<SchemaDocumentType> SchemaType; 00347 typedef GenericValue<EncodingType, AllocatorType> SValue; 00348 friend class GenericSchemaDocument<ValueType, AllocatorType>; 00349 00350 Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : 00351 allocator_(allocator), 00352 enum_(), 00353 enumCount_(), 00354 not_(), 00355 type_((1 << kTotalSchemaType) - 1), // typeless 00356 validatorCount_(), 00357 properties_(), 00358 additionalPropertiesSchema_(), 00359 patternProperties_(), 00360 patternPropertyCount_(), 00361 propertyCount_(), 00362 minProperties_(), 00363 maxProperties_(SizeType(~0)), 00364 additionalProperties_(true), 00365 hasDependencies_(), 00366 hasRequired_(), 00367 hasSchemaDependencies_(), 00368 additionalItemsSchema_(), 00369 itemsList_(), 00370 itemsTuple_(), 00371 itemsTupleCount_(), 00372 minItems_(), 00373 maxItems_(SizeType(~0)), 00374 additionalItems_(true), 00375 uniqueItems_(false), 00376 pattern_(), 00377 minLength_(0), 00378 maxLength_(~SizeType(0)), 00379 exclusiveMinimum_(false), 00380 exclusiveMaximum_(false) 00381 { 00382 typedef typename SchemaDocumentType::ValueType ValueType; 00383 typedef typename ValueType::ConstValueIterator ConstValueIterator; 00384 typedef typename ValueType::ConstMemberIterator ConstMemberIterator; 00385 00386 if (!value.IsObject()) 00387 return; 00388 00389 if (const ValueType* v = GetMember(value, GetTypeString())) { 00390 type_ = 0; 00391 if (v->IsString()) 00392 AddType(*v); 00393 else if (v->IsArray()) 00394 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) 00395 AddType(*itr); 00396 } 00397 00398 if (const ValueType* v = GetMember(value, GetEnumString())) 00399 if (v->IsArray() && v->Size() > 0) { 00400 enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size())); 00401 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { 00402 typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType; 00403 char buffer[256 + 24]; 00404 MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); 00405 EnumHasherType h(&hasherAllocator, 256); 00406 itr->Accept(h); 00407 enum_[enumCount_++] = h.GetHashCode(); 00408 } 00409 } 00410 00411 if (schemaDocument) { 00412 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); 00413 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); 00414 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); 00415 } 00416 00417 if (const ValueType* v = GetMember(value, GetNotString())) { 00418 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); 00419 notValidatorIndex_ = validatorCount_; 00420 validatorCount_++; 00421 } 00422 00423 // Object 00424 00425 const ValueType* properties = GetMember(value, GetPropertiesString()); 00426 const ValueType* required = GetMember(value, GetRequiredString()); 00427 const ValueType* dependencies = GetMember(value, GetDependenciesString()); 00428 { 00429 // Gather properties from properties/required/dependencies 00430 SValue allProperties(kArrayType); 00431 00432 if (properties && properties->IsObject()) 00433 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) 00434 AddUniqueElement(allProperties, itr->name); 00435 00436 if (required && required->IsArray()) 00437 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) 00438 if (itr->IsString()) 00439 AddUniqueElement(allProperties, *itr); 00440 00441 if (dependencies && dependencies->IsObject()) 00442 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { 00443 AddUniqueElement(allProperties, itr->name); 00444 if (itr->value.IsArray()) 00445 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) 00446 if (i->IsString()) 00447 AddUniqueElement(allProperties, *i); 00448 } 00449 00450 if (allProperties.Size() > 0) { 00451 propertyCount_ = allProperties.Size(); 00452 properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_)); 00453 for (SizeType i = 0; i < propertyCount_; i++) { 00454 new (&properties_[i]) Property(); 00455 properties_[i].name = allProperties[i]; 00456 properties_[i].schema = GetTypeless(); 00457 } 00458 } 00459 } 00460 00461 if (properties && properties->IsObject()) { 00462 PointerType q = p.Append(GetPropertiesString(), allocator_); 00463 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { 00464 SizeType index; 00465 if (FindPropertyIndex(itr->name, &index)) 00466 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); 00467 } 00468 } 00469 00470 if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { 00471 PointerType q = p.Append(GetPatternPropertiesString(), allocator_); 00472 patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); 00473 patternPropertyCount_ = 0; 00474 00475 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { 00476 new (&patternProperties_[patternPropertyCount_]) PatternProperty(); 00477 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); 00478 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); 00479 patternPropertyCount_++; 00480 } 00481 } 00482 00483 if (required && required->IsArray()) 00484 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) 00485 if (itr->IsString()) { 00486 SizeType index; 00487 if (FindPropertyIndex(*itr, &index)) { 00488 properties_[index].required = true; 00489 hasRequired_ = true; 00490 } 00491 } 00492 00493 if (dependencies && dependencies->IsObject()) { 00494 PointerType q = p.Append(GetDependenciesString(), allocator_); 00495 hasDependencies_ = true; 00496 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { 00497 SizeType sourceIndex; 00498 if (FindPropertyIndex(itr->name, &sourceIndex)) { 00499 if (itr->value.IsArray()) { 00500 properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_)); 00501 std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); 00502 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { 00503 SizeType targetIndex; 00504 if (FindPropertyIndex(*targetItr, &targetIndex)) 00505 properties_[sourceIndex].dependencies[targetIndex] = true; 00506 } 00507 } 00508 else if (itr->value.IsObject()) { 00509 hasSchemaDependencies_ = true; 00510 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); 00511 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; 00512 validatorCount_++; 00513 } 00514 } 00515 } 00516 } 00517 00518 if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { 00519 if (v->IsBool()) 00520 additionalProperties_ = v->GetBool(); 00521 else if (v->IsObject()) 00522 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); 00523 } 00524 00525 AssignIfExist(minProperties_, value, GetMinPropertiesString()); 00526 AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); 00527 00528 // Array 00529 if (const ValueType* v = GetMember(value, GetItemsString())) { 00530 PointerType q = p.Append(GetItemsString(), allocator_); 00531 if (v->IsObject()) // List validation 00532 schemaDocument->CreateSchema(&itemsList_, q, *v, document); 00533 else if (v->IsArray()) { // Tuple validation 00534 itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size())); 00535 SizeType index = 0; 00536 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) 00537 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); 00538 } 00539 } 00540 00541 AssignIfExist(minItems_, value, GetMinItemsString()); 00542 AssignIfExist(maxItems_, value, GetMaxItemsString()); 00543 00544 if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { 00545 if (v->IsBool()) 00546 additionalItems_ = v->GetBool(); 00547 else if (v->IsObject()) 00548 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); 00549 } 00550 00551 AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); 00552 00553 // String 00554 AssignIfExist(minLength_, value, GetMinLengthString()); 00555 AssignIfExist(maxLength_, value, GetMaxLengthString()); 00556 00557 if (const ValueType* v = GetMember(value, GetPatternString())) 00558 pattern_ = CreatePattern(*v); 00559 00560 // Number 00561 if (const ValueType* v = GetMember(value, GetMinimumString())) 00562 if (v->IsNumber()) 00563 minimum_.CopyFrom(*v, *allocator_); 00564 00565 if (const ValueType* v = GetMember(value, GetMaximumString())) 00566 if (v->IsNumber()) 00567 maximum_.CopyFrom(*v, *allocator_); 00568 00569 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); 00570 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); 00571 00572 if (const ValueType* v = GetMember(value, GetMultipleOfString())) 00573 if (v->IsNumber() && v->GetDouble() > 0.0) 00574 multipleOf_.CopyFrom(*v, *allocator_); 00575 } 00576 00577 ~Schema() { 00578 if (allocator_) { 00579 allocator_->Free(enum_); 00580 } 00581 if (properties_) { 00582 for (SizeType i = 0; i < propertyCount_; i++) 00583 properties_[i].~Property(); 00584 AllocatorType::Free(properties_); 00585 } 00586 if (patternProperties_) { 00587 for (SizeType i = 0; i < patternPropertyCount_; i++) 00588 patternProperties_[i].~PatternProperty(); 00589 AllocatorType::Free(patternProperties_); 00590 } 00591 AllocatorType::Free(itemsTuple_); 00592 #if RAPIDJSON_SCHEMA_HAS_REGEX 00593 if (pattern_) { 00594 pattern_->~RegexType(); 00595 allocator_->Free(pattern_); 00596 } 00597 #endif 00598 } 00599 00600 bool BeginValue(Context& context) const { 00601 if (context.inArray) { 00602 if (uniqueItems_) 00603 context.valueUniqueness = true; 00604 00605 if (itemsList_) 00606 context.valueSchema = itemsList_; 00607 else if (itemsTuple_) { 00608 if (context.arrayElementIndex < itemsTupleCount_) 00609 context.valueSchema = itemsTuple_[context.arrayElementIndex]; 00610 else if (additionalItemsSchema_) 00611 context.valueSchema = additionalItemsSchema_; 00612 else if (additionalItems_) 00613 context.valueSchema = GetTypeless(); 00614 else 00615 RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); 00616 } 00617 else 00618 context.valueSchema = GetTypeless(); 00619 00620 context.arrayElementIndex++; 00621 } 00622 return true; 00623 } 00624 00625 RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { 00626 if (context.patternPropertiesValidatorCount > 0) { 00627 bool otherValid = false; 00628 SizeType count = context.patternPropertiesValidatorCount; 00629 if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) 00630 otherValid = context.patternPropertiesValidators[--count]->IsValid(); 00631 00632 bool patternValid = true; 00633 for (SizeType i = 0; i < count; i++) 00634 if (!context.patternPropertiesValidators[i]->IsValid()) { 00635 patternValid = false; 00636 break; 00637 } 00638 00639 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { 00640 if (!patternValid) 00641 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); 00642 } 00643 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { 00644 if (!patternValid || !otherValid) 00645 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); 00646 } 00647 else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) 00648 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); 00649 } 00650 00651 if (enum_) { 00652 const uint64_t h = context.factory.GetHashCode(context.hasher); 00653 for (SizeType i = 0; i < enumCount_; i++) 00654 if (enum_[i] == h) 00655 goto foundEnum; 00656 RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); 00657 foundEnum:; 00658 } 00659 00660 if (allOf_.schemas) 00661 for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) 00662 if (!context.validators[i]->IsValid()) 00663 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); 00664 00665 if (anyOf_.schemas) { 00666 for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) 00667 if (context.validators[i]->IsValid()) 00668 goto foundAny; 00669 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); 00670 foundAny:; 00671 } 00672 00673 if (oneOf_.schemas) { 00674 bool oneValid = false; 00675 for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) 00676 if (context.validators[i]->IsValid()) { 00677 if (oneValid) 00678 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); 00679 else 00680 oneValid = true; 00681 } 00682 if (!oneValid) 00683 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); 00684 } 00685 00686 if (not_ && context.validators[notValidatorIndex_]->IsValid()) 00687 RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); 00688 00689 return true; 00690 } 00691 00692 bool Null(Context& context) const { 00693 if (!(type_ & (1 << kNullSchemaType))) 00694 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); 00695 return CreateParallelValidator(context); 00696 } 00697 00698 bool Bool(Context& context, bool) const { 00699 if (!(type_ & (1 << kBooleanSchemaType))) 00700 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); 00701 return CreateParallelValidator(context); 00702 } 00703 00704 bool Int(Context& context, int i) const { 00705 if (!CheckInt(context, i)) 00706 return false; 00707 return CreateParallelValidator(context); 00708 } 00709 00710 bool Uint(Context& context, unsigned u) const { 00711 if (!CheckUint(context, u)) 00712 return false; 00713 return CreateParallelValidator(context); 00714 } 00715 00716 bool Int64(Context& context, int64_t i) const { 00717 if (!CheckInt(context, i)) 00718 return false; 00719 return CreateParallelValidator(context); 00720 } 00721 00722 bool Uint64(Context& context, uint64_t u) const { 00723 if (!CheckUint(context, u)) 00724 return false; 00725 return CreateParallelValidator(context); 00726 } 00727 00728 bool Double(Context& context, double d) const { 00729 if (!(type_ & (1 << kNumberSchemaType))) 00730 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); 00731 00732 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) 00733 return false; 00734 00735 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) 00736 return false; 00737 00738 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) 00739 return false; 00740 00741 return CreateParallelValidator(context); 00742 } 00743 00744 bool String(Context& context, const Ch* str, SizeType length, bool) const { 00745 if (!(type_ & (1 << kStringSchemaType))) 00746 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); 00747 00748 if (minLength_ != 0 || maxLength_ != SizeType(~0)) { 00749 SizeType count; 00750 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) { 00751 if (count < minLength_) 00752 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); 00753 if (count > maxLength_) 00754 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); 00755 } 00756 } 00757 00758 if (pattern_ && !IsPatternMatch(pattern_, str, length)) 00759 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); 00760 00761 return CreateParallelValidator(context); 00762 } 00763 00764 bool StartObject(Context& context) const { 00765 if (!(type_ & (1 << kObjectSchemaType))) 00766 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); 00767 00768 if (hasDependencies_ || hasRequired_) { 00769 context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_)); 00770 std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); 00771 } 00772 00773 if (patternProperties_) { // pre-allocate schema array 00774 SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType 00775 context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count)); 00776 context.patternPropertiesSchemaCount = 0; 00777 std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); 00778 } 00779 00780 return CreateParallelValidator(context); 00781 } 00782 00783 bool Key(Context& context, const Ch* str, SizeType len, bool) const { 00784 if (patternProperties_) { 00785 context.patternPropertiesSchemaCount = 0; 00786 for (SizeType i = 0; i < patternPropertyCount_; i++) 00787 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) 00788 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; 00789 } 00790 00791 SizeType index; 00792 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { 00793 if (context.patternPropertiesSchemaCount > 0) { 00794 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; 00795 context.valueSchema = GetTypeless(); 00796 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; 00797 } 00798 else 00799 context.valueSchema = properties_[index].schema; 00800 00801 if (context.propertyExist) 00802 context.propertyExist[index] = true; 00803 00804 return true; 00805 } 00806 00807 if (additionalPropertiesSchema_) { 00808 if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { 00809 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; 00810 context.valueSchema = GetTypeless(); 00811 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; 00812 } 00813 else 00814 context.valueSchema = additionalPropertiesSchema_; 00815 return true; 00816 } 00817 else if (additionalProperties_) { 00818 context.valueSchema = GetTypeless(); 00819 return true; 00820 } 00821 00822 if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties 00823 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); 00824 00825 return true; 00826 } 00827 00828 bool EndObject(Context& context, SizeType memberCount) const { 00829 if (hasRequired_) 00830 for (SizeType index = 0; index < propertyCount_; index++) 00831 if (properties_[index].required) 00832 if (!context.propertyExist[index]) 00833 RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); 00834 00835 if (memberCount < minProperties_) 00836 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); 00837 00838 if (memberCount > maxProperties_) 00839 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); 00840 00841 if (hasDependencies_) { 00842 for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) 00843 if (context.propertyExist[sourceIndex]) { 00844 if (properties_[sourceIndex].dependencies) { 00845 for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) 00846 if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) 00847 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); 00848 } 00849 else if (properties_[sourceIndex].dependenciesSchema) 00850 if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) 00851 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); 00852 } 00853 } 00854 00855 return true; 00856 } 00857 00858 bool StartArray(Context& context) const { 00859 if (!(type_ & (1 << kArraySchemaType))) 00860 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); 00861 00862 context.arrayElementIndex = 0; 00863 context.inArray = true; 00864 00865 return CreateParallelValidator(context); 00866 } 00867 00868 bool EndArray(Context& context, SizeType elementCount) const { 00869 context.inArray = false; 00870 00871 if (elementCount < minItems_) 00872 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); 00873 00874 if (elementCount > maxItems_) 00875 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); 00876 00877 return true; 00878 } 00879 00880 // Generate functions for string literal according to Ch 00881 #define RAPIDJSON_STRING_(name, ...) \ 00882 static const ValueType& Get##name##String() {\ 00883 static const Ch s[] = { __VA_ARGS__, '\0' };\ 00884 static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ 00885 return v;\ 00886 } 00887 00888 RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') 00889 RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') 00890 RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') 00891 RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') 00892 RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') 00893 RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') 00894 RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') 00895 RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') 00896 RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') 00897 RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') 00898 RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') 00899 RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') 00900 RAPIDJSON_STRING_(Not, 'n', 'o', 't') 00901 RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') 00902 RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') 00903 RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') 00904 RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') 00905 RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') 00906 RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') 00907 RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') 00908 RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') 00909 RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') 00910 RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') 00911 RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') 00912 RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') 00913 RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') 00914 RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') 00915 RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') 00916 RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') 00917 RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') 00918 RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') 00919 RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') 00920 RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') 00921 00922 #undef RAPIDJSON_STRING_ 00923 00924 private: 00925 enum SchemaValueType { 00926 kNullSchemaType, 00927 kBooleanSchemaType, 00928 kObjectSchemaType, 00929 kArraySchemaType, 00930 kStringSchemaType, 00931 kNumberSchemaType, 00932 kIntegerSchemaType, 00933 kTotalSchemaType 00934 }; 00935 00936 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX 00937 typedef internal::GenericRegex<EncodingType> RegexType; 00938 #elif RAPIDJSON_SCHEMA_USE_STDREGEX 00939 typedef std::basic_regex<Ch> RegexType; 00940 #else 00941 typedef char RegexType; 00942 #endif 00943 00944 struct SchemaArray { 00945 SchemaArray() : schemas(), count() {} 00946 ~SchemaArray() { AllocatorType::Free(schemas); } 00947 const SchemaType** schemas; 00948 SizeType begin; // begin index of context.validators 00949 SizeType count; 00950 }; 00951 00952 static const SchemaType* GetTypeless() { 00953 static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); 00954 return &typeless; 00955 } 00956 00957 template <typename V1, typename V2> 00958 void AddUniqueElement(V1& a, const V2& v) { 00959 for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) 00960 if (*itr == v) 00961 return; 00962 V1 c(v, *allocator_); 00963 a.PushBack(c, *allocator_); 00964 } 00965 00966 static const ValueType* GetMember(const ValueType& value, const ValueType& name) { 00967 typename ValueType::ConstMemberIterator itr = value.FindMember(name); 00968 return itr != value.MemberEnd() ? &(itr->value) : 0; 00969 } 00970 00971 static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { 00972 if (const ValueType* v = GetMember(value, name)) 00973 if (v->IsBool()) 00974 out = v->GetBool(); 00975 } 00976 00977 static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { 00978 if (const ValueType* v = GetMember(value, name)) 00979 if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) 00980 out = static_cast<SizeType>(v->GetUint64()); 00981 } 00982 00983 void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { 00984 if (const ValueType* v = GetMember(value, name)) { 00985 if (v->IsArray() && v->Size() > 0) { 00986 PointerType q = p.Append(name, allocator_); 00987 out.count = v->Size(); 00988 out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*))); 00989 memset(out.schemas, 0, sizeof(Schema*)* out.count); 00990 for (SizeType i = 0; i < out.count; i++) 00991 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); 00992 out.begin = validatorCount_; 00993 validatorCount_ += out.count; 00994 } 00995 } 00996 } 00997 00998 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX 00999 template <typename ValueType> 01000 RegexType* CreatePattern(const ValueType& value) { 01001 if (value.IsString()) { 01002 RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); 01003 if (!r->IsValid()) { 01004 r->~RegexType(); 01005 AllocatorType::Free(r); 01006 r = 0; 01007 } 01008 return r; 01009 } 01010 return 0; 01011 } 01012 01013 static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { 01014 GenericRegexSearch<RegexType> rs(*pattern); 01015 return rs.Search(str); 01016 } 01017 #elif RAPIDJSON_SCHEMA_USE_STDREGEX 01018 template <typename ValueType> 01019 RegexType* CreatePattern(const ValueType& value) { 01020 if (value.IsString()) 01021 try { 01022 return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); 01023 } 01024 catch (const std::regex_error&) { 01025 } 01026 return 0; 01027 } 01028 01029 static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { 01030 std::match_results<const Ch*> r; 01031 return std::regex_search(str, str + length, r, *pattern); 01032 } 01033 #else 01034 template <typename ValueType> 01035 RegexType* CreatePattern(const ValueType&) { return 0; } 01036 01037 static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } 01038 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX 01039 01040 void AddType(const ValueType& type) { 01041 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; 01042 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; 01043 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; 01044 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; 01045 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; 01046 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; 01047 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); 01048 } 01049 01050 bool CreateParallelValidator(Context& context) const { 01051 if (enum_ || context.arrayUniqueness) 01052 context.hasher = context.factory.CreateHasher(); 01053 01054 if (validatorCount_) { 01055 RAPIDJSON_ASSERT(context.validators == 0); 01056 context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); 01057 context.validatorCount = validatorCount_; 01058 01059 if (allOf_.schemas) 01060 CreateSchemaValidators(context, allOf_); 01061 01062 if (anyOf_.schemas) 01063 CreateSchemaValidators(context, anyOf_); 01064 01065 if (oneOf_.schemas) 01066 CreateSchemaValidators(context, oneOf_); 01067 01068 if (not_) 01069 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); 01070 01071 if (hasSchemaDependencies_) { 01072 for (SizeType i = 0; i < propertyCount_; i++) 01073 if (properties_[i].dependenciesSchema) 01074 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); 01075 } 01076 } 01077 01078 return true; 01079 } 01080 01081 void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { 01082 for (SizeType i = 0; i < schemas.count; i++) 01083 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); 01084 } 01085 01086 // O(n) 01087 bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { 01088 SizeType len = name.GetStringLength(); 01089 const Ch* str = name.GetString(); 01090 for (SizeType index = 0; index < propertyCount_; index++) 01091 if (properties_[index].name.GetStringLength() == len && 01092 (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) 01093 { 01094 *outIndex = index; 01095 return true; 01096 } 01097 return false; 01098 } 01099 01100 bool CheckInt(Context& context, int64_t i) const { 01101 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) 01102 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); 01103 01104 if (!minimum_.IsNull()) { 01105 if (minimum_.IsInt64()) { 01106 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) 01107 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); 01108 } 01109 else if (minimum_.IsUint64()) { 01110 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() 01111 } 01112 else if (!CheckDoubleMinimum(context, static_cast<double>(i))) 01113 return false; 01114 } 01115 01116 if (!maximum_.IsNull()) { 01117 if (maximum_.IsInt64()) { 01118 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) 01119 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); 01120 } 01121 else if (maximum_.IsUint64()) 01122 /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64() 01123 else if (!CheckDoubleMaximum(context, static_cast<double>(i))) 01124 return false; 01125 } 01126 01127 if (!multipleOf_.IsNull()) { 01128 if (multipleOf_.IsUint64()) { 01129 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) 01130 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); 01131 } 01132 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i))) 01133 return false; 01134 } 01135 01136 return true; 01137 } 01138 01139 bool CheckUint(Context& context, uint64_t i) const { 01140 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) 01141 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); 01142 01143 if (!minimum_.IsNull()) { 01144 if (minimum_.IsUint64()) { 01145 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) 01146 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); 01147 } 01148 else if (minimum_.IsInt64()) 01149 /* do nothing */; // i >= 0 > minimum.Getint64() 01150 else if (!CheckDoubleMinimum(context, static_cast<double>(i))) 01151 return false; 01152 } 01153 01154 if (!maximum_.IsNull()) { 01155 if (maximum_.IsUint64()) { 01156 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) 01157 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); 01158 } 01159 else if (maximum_.IsInt64()) 01160 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ 01161 else if (!CheckDoubleMaximum(context, static_cast<double>(i))) 01162 return false; 01163 } 01164 01165 if (!multipleOf_.IsNull()) { 01166 if (multipleOf_.IsUint64()) { 01167 if (i % multipleOf_.GetUint64() != 0) 01168 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); 01169 } 01170 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i))) 01171 return false; 01172 } 01173 01174 return true; 01175 } 01176 01177 bool CheckDoubleMinimum(Context& context, double d) const { 01178 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) 01179 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); 01180 return true; 01181 } 01182 01183 bool CheckDoubleMaximum(Context& context, double d) const { 01184 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) 01185 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); 01186 return true; 01187 } 01188 01189 bool CheckDoubleMultipleOf(Context& context, double d) const { 01190 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); 01191 double q = std::floor(a / b); 01192 double r = a - q * b; 01193 if (r > 0.0) 01194 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); 01195 return true; 01196 } 01197 01198 struct Property { 01199 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} 01200 ~Property() { AllocatorType::Free(dependencies); } 01201 SValue name; 01202 const SchemaType* schema; 01203 const SchemaType* dependenciesSchema; 01204 SizeType dependenciesValidatorIndex; 01205 bool* dependencies; 01206 bool required; 01207 }; 01208 01209 struct PatternProperty { 01210 PatternProperty() : schema(), pattern() {} 01211 ~PatternProperty() { 01212 if (pattern) { 01213 pattern->~RegexType(); 01214 AllocatorType::Free(pattern); 01215 } 01216 } 01217 const SchemaType* schema; 01218 RegexType* pattern; 01219 }; 01220 01221 AllocatorType* allocator_; 01222 uint64_t* enum_; 01223 SizeType enumCount_; 01224 SchemaArray allOf_; 01225 SchemaArray anyOf_; 01226 SchemaArray oneOf_; 01227 const SchemaType* not_; 01228 unsigned type_; // bitmask of kSchemaType 01229 SizeType validatorCount_; 01230 SizeType notValidatorIndex_; 01231 01232 Property* properties_; 01233 const SchemaType* additionalPropertiesSchema_; 01234 PatternProperty* patternProperties_; 01235 SizeType patternPropertyCount_; 01236 SizeType propertyCount_; 01237 SizeType minProperties_; 01238 SizeType maxProperties_; 01239 bool additionalProperties_; 01240 bool hasDependencies_; 01241 bool hasRequired_; 01242 bool hasSchemaDependencies_; 01243 01244 const SchemaType* additionalItemsSchema_; 01245 const SchemaType* itemsList_; 01246 const SchemaType** itemsTuple_; 01247 SizeType itemsTupleCount_; 01248 SizeType minItems_; 01249 SizeType maxItems_; 01250 bool additionalItems_; 01251 bool uniqueItems_; 01252 01253 RegexType* pattern_; 01254 SizeType minLength_; 01255 SizeType maxLength_; 01256 01257 SValue minimum_; 01258 SValue maximum_; 01259 SValue multipleOf_; 01260 bool exclusiveMinimum_; 01261 bool exclusiveMaximum_; 01262 }; 01263 01264 template<typename Stack, typename Ch> 01265 struct TokenHelper { 01266 RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { 01267 *documentStack.template Push<Ch>() = '/'; 01268 char buffer[21]; 01269 size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); 01270 for (size_t i = 0; i < length; i++) 01271 *documentStack.template Push<Ch>() = buffer[i]; 01272 } 01273 }; 01274 01275 // Partial specialized version for char to prevent buffer copying. 01276 template <typename Stack> 01277 struct TokenHelper<Stack, char> { 01278 RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { 01279 if (sizeof(SizeType) == 4) { 01280 char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint 01281 *buffer++ = '/'; 01282 const char* end = internal::u32toa(index, buffer); 01283 documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer))); 01284 } 01285 else { 01286 char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64 01287 *buffer++ = '/'; 01288 const char* end = internal::u64toa(index, buffer); 01289 documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer))); 01290 } 01291 } 01292 }; 01293 01294 } // namespace internal 01295 01296 /////////////////////////////////////////////////////////////////////////////// 01297 // IGenericRemoteSchemaDocumentProvider 01298 01299 template <typename SchemaDocumentType> 01300 class IGenericRemoteSchemaDocumentProvider { 01301 public: 01302 typedef typename SchemaDocumentType::Ch Ch; 01303 01304 virtual ~IGenericRemoteSchemaDocumentProvider() {} 01305 virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; 01306 }; 01307 01308 /////////////////////////////////////////////////////////////////////////////// 01309 // GenericSchemaDocument 01310 01311 //! JSON schema document. 01312 /*! 01313 A JSON schema document is a compiled version of a JSON schema. 01314 It is basically a tree of internal::Schema. 01315 01316 \note This is an immutable class (i.e. its instance cannot be modified after construction). 01317 \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. 01318 \tparam Allocator Allocator type for allocating memory of this document. 01319 */ 01320 template <typename ValueT, typename Allocator = CrtAllocator> 01321 class GenericSchemaDocument { 01322 public: 01323 typedef ValueT ValueType; 01324 typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType; 01325 typedef Allocator AllocatorType; 01326 typedef typename ValueType::EncodingType EncodingType; 01327 typedef typename EncodingType::Ch Ch; 01328 typedef internal::Schema<GenericSchemaDocument> SchemaType; 01329 typedef GenericPointer<ValueType, Allocator> PointerType; 01330 friend class internal::Schema<GenericSchemaDocument>; 01331 template <typename, typename, typename> 01332 friend class GenericSchemaValidator; 01333 01334 //! Constructor. 01335 /*! 01336 Compile a JSON document into schema document. 01337 01338 \param document A JSON document as source. 01339 \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. 01340 \param allocator An optional allocator instance for allocating memory. Can be null. 01341 */ 01342 explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : 01343 remoteProvider_(remoteProvider), 01344 allocator_(allocator), 01345 ownAllocator_(), 01346 root_(), 01347 schemaMap_(allocator, kInitialSchemaMapSize), 01348 schemaRef_(allocator, kInitialSchemaRefSize) 01349 { 01350 if (!allocator_) 01351 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); 01352 01353 // Generate root schema, it will call CreateSchema() to create sub-schemas, 01354 // And call AddRefSchema() if there are $ref. 01355 CreateSchemaRecursive(&root_, PointerType(), document, document); 01356 01357 // Resolve $ref 01358 while (!schemaRef_.Empty()) { 01359 SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1); 01360 if (const SchemaType* s = GetSchema(refEntry->target)) { 01361 if (refEntry->schema) 01362 *refEntry->schema = s; 01363 01364 // Create entry in map if not exist 01365 if (!GetSchema(refEntry->source)) { 01366 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_); 01367 } 01368 } 01369 refEntry->~SchemaRefEntry(); 01370 } 01371 01372 RAPIDJSON_ASSERT(root_ != 0); 01373 01374 schemaRef_.ShrinkToFit(); // Deallocate all memory for ref 01375 } 01376 01377 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 01378 //! Move constructor in C++11 01379 GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : 01380 remoteProvider_(rhs.remoteProvider_), 01381 allocator_(rhs.allocator_), 01382 ownAllocator_(rhs.ownAllocator_), 01383 root_(rhs.root_), 01384 schemaMap_(std::move(rhs.schemaMap_)), 01385 schemaRef_(std::move(rhs.schemaRef_)) 01386 { 01387 rhs.remoteProvider_ = 0; 01388 rhs.allocator_ = 0; 01389 rhs.ownAllocator_ = 0; 01390 } 01391 #endif 01392 01393 //! Destructor 01394 ~GenericSchemaDocument() { 01395 while (!schemaMap_.Empty()) 01396 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry(); 01397 01398 RAPIDJSON_DELETE(ownAllocator_); 01399 } 01400 01401 //! Get the root schema. 01402 const SchemaType& GetRoot() const { return *root_; } 01403 01404 private: 01405 //! Prohibit copying 01406 GenericSchemaDocument(const GenericSchemaDocument&); 01407 //! Prohibit assignment 01408 GenericSchemaDocument& operator=(const GenericSchemaDocument&); 01409 01410 struct SchemaRefEntry { 01411 SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} 01412 PointerType source; 01413 PointerType target; 01414 const SchemaType** schema; 01415 }; 01416 01417 struct SchemaEntry { 01418 SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} 01419 ~SchemaEntry() { 01420 if (owned) { 01421 schema->~SchemaType(); 01422 Allocator::Free(schema); 01423 } 01424 } 01425 PointerType pointer; 01426 SchemaType* schema; 01427 bool owned; 01428 }; 01429 01430 void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { 01431 if (schema) 01432 *schema = SchemaType::GetTypeless(); 01433 01434 if (v.GetType() == kObjectType) { 01435 const SchemaType* s = GetSchema(pointer); 01436 if (!s) 01437 CreateSchema(schema, pointer, v, document); 01438 01439 for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) 01440 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); 01441 } 01442 else if (v.GetType() == kArrayType) 01443 for (SizeType i = 0; i < v.Size(); i++) 01444 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); 01445 } 01446 01447 void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { 01448 RAPIDJSON_ASSERT(pointer.IsValid()); 01449 if (v.IsObject()) { 01450 if (!HandleRefSchema(pointer, schema, v, document)) { 01451 SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); 01452 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_); 01453 if (schema) 01454 *schema = s; 01455 } 01456 } 01457 } 01458 01459 bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { 01460 static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; 01461 static const ValueType kRefValue(kRefString, 4); 01462 01463 typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); 01464 if (itr == v.MemberEnd()) 01465 return false; 01466 01467 if (itr->value.IsString()) { 01468 SizeType len = itr->value.GetStringLength(); 01469 if (len > 0) { 01470 const Ch* s = itr->value.GetString(); 01471 SizeType i = 0; 01472 while (i < len && s[i] != '#') // Find the first # 01473 i++; 01474 01475 if (i > 0) { // Remote reference, resolve immediately 01476 if (remoteProvider_) { 01477 if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) { 01478 PointerType pointer(&s[i], len - i, allocator_); 01479 if (pointer.IsValid()) { 01480 if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { 01481 if (schema) 01482 *schema = sc; 01483 return true; 01484 } 01485 } 01486 } 01487 } 01488 } 01489 else if (s[i] == '#') { // Local reference, defer resolution 01490 PointerType pointer(&s[i], len - i, allocator_); 01491 if (pointer.IsValid()) { 01492 if (const ValueType* nv = pointer.Get(document)) 01493 if (HandleRefSchema(source, schema, *nv, document)) 01494 return true; 01495 01496 new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_); 01497 return true; 01498 } 01499 } 01500 } 01501 } 01502 return false; 01503 } 01504 01505 const SchemaType* GetSchema(const PointerType& pointer) const { 01506 for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target) 01507 if (pointer == target->pointer) 01508 return target->schema; 01509 return 0; 01510 } 01511 01512 PointerType GetPointer(const SchemaType* schema) const { 01513 for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target) 01514 if (schema == target->schema) 01515 return target->pointer; 01516 return PointerType(); 01517 } 01518 01519 static const size_t kInitialSchemaMapSize = 64; 01520 static const size_t kInitialSchemaRefSize = 64; 01521 01522 IRemoteSchemaDocumentProviderType* remoteProvider_; 01523 Allocator *allocator_; 01524 Allocator *ownAllocator_; 01525 const SchemaType* root_; //!< Root schema. 01526 internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas 01527 internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref 01528 }; 01529 01530 //! GenericSchemaDocument using Value type. 01531 typedef GenericSchemaDocument<Value> SchemaDocument; 01532 //! IGenericRemoteSchemaDocumentProvider using SchemaDocument. 01533 typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider; 01534 01535 /////////////////////////////////////////////////////////////////////////////// 01536 // GenericSchemaValidator 01537 01538 //! JSON Schema Validator. 01539 /*! 01540 A SAX style JSON schema validator. 01541 It uses a \c GenericSchemaDocument to validate SAX events. 01542 It delegates the incoming SAX events to an output handler. 01543 The default output handler does nothing. 01544 It can be reused multiple times by calling \c Reset(). 01545 01546 \tparam SchemaDocumentType Type of schema document. 01547 \tparam OutputHandler Type of output handler. Default handler does nothing. 01548 \tparam StateAllocator Allocator for storing the internal validation states. 01549 */ 01550 template < 01551 typename SchemaDocumentType, 01552 typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>, 01553 typename StateAllocator = CrtAllocator> 01554 class GenericSchemaValidator : 01555 public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>, 01556 public internal::ISchemaValidator 01557 { 01558 public: 01559 typedef typename SchemaDocumentType::SchemaType SchemaType; 01560 typedef typename SchemaDocumentType::PointerType PointerType; 01561 typedef typename SchemaType::EncodingType EncodingType; 01562 typedef typename EncodingType::Ch Ch; 01563 01564 //! Constructor without output handler. 01565 /*! 01566 \param schemaDocument The schema document to conform to. 01567 \param allocator Optional allocator for storing internal validation states. 01568 \param schemaStackCapacity Optional initial capacity of schema path stack. 01569 \param documentStackCapacity Optional initial capacity of document path stack. 01570 */ 01571 GenericSchemaValidator( 01572 const SchemaDocumentType& schemaDocument, 01573 StateAllocator* allocator = 0, 01574 size_t schemaStackCapacity = kDefaultSchemaStackCapacity, 01575 size_t documentStackCapacity = kDefaultDocumentStackCapacity) 01576 : 01577 schemaDocument_(&schemaDocument), 01578 root_(schemaDocument.GetRoot()), 01579 outputHandler_(GetNullHandler()), 01580 stateAllocator_(allocator), 01581 ownStateAllocator_(0), 01582 schemaStack_(allocator, schemaStackCapacity), 01583 documentStack_(allocator, documentStackCapacity), 01584 valid_(true) 01585 #if RAPIDJSON_SCHEMA_VERBOSE 01586 , depth_(0) 01587 #endif 01588 { 01589 } 01590 01591 //! Constructor with output handler. 01592 /*! 01593 \param schemaDocument The schema document to conform to. 01594 \param allocator Optional allocator for storing internal validation states. 01595 \param schemaStackCapacity Optional initial capacity of schema path stack. 01596 \param documentStackCapacity Optional initial capacity of document path stack. 01597 */ 01598 GenericSchemaValidator( 01599 const SchemaDocumentType& schemaDocument, 01600 OutputHandler& outputHandler, 01601 StateAllocator* allocator = 0, 01602 size_t schemaStackCapacity = kDefaultSchemaStackCapacity, 01603 size_t documentStackCapacity = kDefaultDocumentStackCapacity) 01604 : 01605 schemaDocument_(&schemaDocument), 01606 root_(schemaDocument.GetRoot()), 01607 outputHandler_(outputHandler), 01608 stateAllocator_(allocator), 01609 ownStateAllocator_(0), 01610 schemaStack_(allocator, schemaStackCapacity), 01611 documentStack_(allocator, documentStackCapacity), 01612 valid_(true) 01613 #if RAPIDJSON_SCHEMA_VERBOSE 01614 , depth_(0) 01615 #endif 01616 { 01617 } 01618 01619 //! Destructor. 01620 ~GenericSchemaValidator() { 01621 Reset(); 01622 RAPIDJSON_DELETE(ownStateAllocator_); 01623 } 01624 01625 //! Reset the internal states. 01626 void Reset() { 01627 while (!schemaStack_.Empty()) 01628 PopSchema(); 01629 documentStack_.Clear(); 01630 valid_ = true; 01631 } 01632 01633 //! Checks whether the current state is valid. 01634 // Implementation of ISchemaValidator 01635 virtual bool IsValid() const { return valid_; } 01636 01637 //! Gets the JSON pointer pointed to the invalid schema. 01638 PointerType GetInvalidSchemaPointer() const { 01639 return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema()); 01640 } 01641 01642 //! Gets the keyword of invalid schema. 01643 const Ch* GetInvalidSchemaKeyword() const { 01644 return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; 01645 } 01646 01647 //! Gets the JSON pointer pointed to the invalid value. 01648 PointerType GetInvalidDocumentPointer() const { 01649 return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch)); 01650 } 01651 01652 #if RAPIDJSON_SCHEMA_VERBOSE 01653 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ 01654 RAPIDJSON_MULTILINEMACRO_BEGIN\ 01655 *documentStack_.template Push<Ch>() = '\0';\ 01656 documentStack_.template Pop<Ch>(1);\ 01657 internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\ 01658 RAPIDJSON_MULTILINEMACRO_END 01659 #else 01660 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() 01661 #endif 01662 01663 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ 01664 if (!valid_) return false; \ 01665 if (!BeginValue() || !CurrentSchema().method arg1) {\ 01666 RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ 01667 return valid_ = false;\ 01668 } 01669 01670 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ 01671 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\ 01672 if (context->hasher)\ 01673 static_cast<HasherType*>(context->hasher)->method arg2;\ 01674 if (context->validators)\ 01675 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ 01676 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\ 01677 if (context->patternPropertiesValidators)\ 01678 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ 01679 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\ 01680 } 01681 01682 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ 01683 return valid_ = EndValue() && outputHandler_.method arg2 01684 01685 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ 01686 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ 01687 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ 01688 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) 01689 01690 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } 01691 bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } 01692 bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } 01693 bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } 01694 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } 01695 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } 01696 bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } 01697 bool RawNumber(const Ch* str, SizeType length, bool copy) 01698 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } 01699 bool String(const Ch* str, SizeType length, bool copy) 01700 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } 01701 01702 bool StartObject() { 01703 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); 01704 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); 01705 return valid_ = outputHandler_.StartObject(); 01706 } 01707 01708 bool Key(const Ch* str, SizeType len, bool copy) { 01709 if (!valid_) return false; 01710 AppendToken(str, len); 01711 if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; 01712 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); 01713 return valid_ = outputHandler_.Key(str, len, copy); 01714 } 01715 01716 bool EndObject(SizeType memberCount) { 01717 if (!valid_) return false; 01718 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); 01719 if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; 01720 RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); 01721 } 01722 01723 bool StartArray() { 01724 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); 01725 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); 01726 return valid_ = outputHandler_.StartArray(); 01727 } 01728 01729 bool EndArray(SizeType elementCount) { 01730 if (!valid_) return false; 01731 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); 01732 if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; 01733 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); 01734 } 01735 01736 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ 01737 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ 01738 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ 01739 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ 01740 01741 // Implementation of ISchemaStateFactory<SchemaType> 01742 virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { 01743 return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, 01744 #if RAPIDJSON_SCHEMA_VERBOSE 01745 depth_ + 1, 01746 #endif 01747 &GetStateAllocator()); 01748 } 01749 01750 virtual void DestroySchemaValidator(ISchemaValidator* validator) { 01751 GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator); 01752 v->~GenericSchemaValidator(); 01753 StateAllocator::Free(v); 01754 } 01755 01756 virtual void* CreateHasher() { 01757 return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); 01758 } 01759 01760 virtual uint64_t GetHashCode(void* hasher) { 01761 return static_cast<HasherType*>(hasher)->GetHashCode(); 01762 } 01763 01764 virtual void DestroryHasher(void* hasher) { 01765 HasherType* h = static_cast<HasherType*>(hasher); 01766 h->~HasherType(); 01767 StateAllocator::Free(h); 01768 } 01769 01770 virtual void* MallocState(size_t size) { 01771 return GetStateAllocator().Malloc(size); 01772 } 01773 01774 virtual void FreeState(void* p) { 01775 return StateAllocator::Free(p); 01776 } 01777 01778 private: 01779 typedef typename SchemaType::Context Context; 01780 typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray; 01781 typedef internal::Hasher<EncodingType, StateAllocator> HasherType; 01782 01783 GenericSchemaValidator( 01784 const SchemaDocumentType& schemaDocument, 01785 const SchemaType& root, 01786 #if RAPIDJSON_SCHEMA_VERBOSE 01787 unsigned depth, 01788 #endif 01789 StateAllocator* allocator = 0, 01790 size_t schemaStackCapacity = kDefaultSchemaStackCapacity, 01791 size_t documentStackCapacity = kDefaultDocumentStackCapacity) 01792 : 01793 schemaDocument_(&schemaDocument), 01794 root_(root), 01795 outputHandler_(GetNullHandler()), 01796 stateAllocator_(allocator), 01797 ownStateAllocator_(0), 01798 schemaStack_(allocator, schemaStackCapacity), 01799 documentStack_(allocator, documentStackCapacity), 01800 valid_(true) 01801 #if RAPIDJSON_SCHEMA_VERBOSE 01802 , depth_(depth) 01803 #endif 01804 { 01805 } 01806 01807 StateAllocator& GetStateAllocator() { 01808 if (!stateAllocator_) 01809 stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator()); 01810 return *stateAllocator_; 01811 } 01812 01813 bool BeginValue() { 01814 if (schemaStack_.Empty()) 01815 PushSchema(root_); 01816 else { 01817 if (CurrentContext().inArray) 01818 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); 01819 01820 if (!CurrentSchema().BeginValue(CurrentContext())) 01821 return false; 01822 01823 SizeType count = CurrentContext().patternPropertiesSchemaCount; 01824 const SchemaType** sa = CurrentContext().patternPropertiesSchemas; 01825 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; 01826 bool valueUniqueness = CurrentContext().valueUniqueness; 01827 if (CurrentContext().valueSchema) 01828 PushSchema(*CurrentContext().valueSchema); 01829 01830 if (count > 0) { 01831 CurrentContext().objectPatternValidatorType = patternValidatorType; 01832 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; 01833 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; 01834 va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count)); 01835 for (SizeType i = 0; i < count; i++) 01836 va[validatorCount++] = CreateSchemaValidator(*sa[i]); 01837 } 01838 01839 CurrentContext().arrayUniqueness = valueUniqueness; 01840 } 01841 return true; 01842 } 01843 01844 bool EndValue() { 01845 if (!CurrentSchema().EndValue(CurrentContext())) 01846 return false; 01847 01848 #if RAPIDJSON_SCHEMA_VERBOSE 01849 GenericStringBuffer<EncodingType> sb; 01850 schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); 01851 01852 *documentStack_.template Push<Ch>() = '\0'; 01853 documentStack_.template Pop<Ch>(1); 01854 internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>()); 01855 #endif 01856 01857 uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0; 01858 01859 PopSchema(); 01860 01861 if (!schemaStack_.Empty()) { 01862 Context& context = CurrentContext(); 01863 if (context.valueUniqueness) { 01864 HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes); 01865 if (!a) 01866 CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); 01867 for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) 01868 if (itr->GetUint64() == h) 01869 RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); 01870 a->PushBack(h, GetStateAllocator()); 01871 } 01872 } 01873 01874 // Remove the last token of document pointer 01875 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/') 01876 ; 01877 01878 return true; 01879 } 01880 01881 void AppendToken(const Ch* str, SizeType len) { 01882 documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters 01883 *documentStack_.template PushUnsafe<Ch>() = '/'; 01884 for (SizeType i = 0; i < len; i++) { 01885 if (str[i] == '~') { 01886 *documentStack_.template PushUnsafe<Ch>() = '~'; 01887 *documentStack_.template PushUnsafe<Ch>() = '0'; 01888 } 01889 else if (str[i] == '/') { 01890 *documentStack_.template PushUnsafe<Ch>() = '~'; 01891 *documentStack_.template PushUnsafe<Ch>() = '1'; 01892 } 01893 else 01894 *documentStack_.template PushUnsafe<Ch>() = str[i]; 01895 } 01896 } 01897 01898 RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); } 01899 01900 RAPIDJSON_FORCEINLINE void PopSchema() { 01901 Context* c = schemaStack_.template Pop<Context>(1); 01902 if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) { 01903 a->~HashCodeArray(); 01904 StateAllocator::Free(a); 01905 } 01906 c->~Context(); 01907 } 01908 01909 const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; } 01910 Context& CurrentContext() { return *schemaStack_.template Top<Context>(); } 01911 const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); } 01912 01913 static OutputHandler& GetNullHandler() { 01914 static OutputHandler nullHandler; 01915 return nullHandler; 01916 } 01917 01918 static const size_t kDefaultSchemaStackCapacity = 1024; 01919 static const size_t kDefaultDocumentStackCapacity = 256; 01920 const SchemaDocumentType* schemaDocument_; 01921 const SchemaType& root_; 01922 OutputHandler& outputHandler_; 01923 StateAllocator* stateAllocator_; 01924 StateAllocator* ownStateAllocator_; 01925 internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) 01926 internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch) 01927 bool valid_; 01928 #if RAPIDJSON_SCHEMA_VERBOSE 01929 unsigned depth_; 01930 #endif 01931 }; 01932 01933 typedef GenericSchemaValidator<SchemaDocument> SchemaValidator; 01934 01935 /////////////////////////////////////////////////////////////////////////////// 01936 // SchemaValidatingReader 01937 01938 //! A helper class for parsing with validation. 01939 /*! 01940 This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). 01941 01942 \tparam parseFlags Combination of \ref ParseFlag. 01943 \tparam InputStream Type of input stream, implementing Stream concept. 01944 \tparam SourceEncoding Encoding of the input stream. 01945 \tparam SchemaDocumentType Type of schema document. 01946 \tparam StackAllocator Allocator type for stack. 01947 */ 01948 template < 01949 unsigned parseFlags, 01950 typename InputStream, 01951 typename SourceEncoding, 01952 typename SchemaDocumentType = SchemaDocument, 01953 typename StackAllocator = CrtAllocator> 01954 class SchemaValidatingReader { 01955 public: 01956 typedef typename SchemaDocumentType::PointerType PointerType; 01957 typedef typename InputStream::Ch Ch; 01958 01959 //! Constructor 01960 /*! 01961 \param is Input stream. 01962 \param sd Schema document. 01963 */ 01964 SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {} 01965 01966 template <typename Handler> 01967 bool operator()(Handler& handler) { 01968 GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader; 01969 GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler); 01970 parseResult_ = reader.template Parse<parseFlags>(is_, validator); 01971 01972 isValid_ = validator.IsValid(); 01973 if (isValid_) { 01974 invalidSchemaPointer_ = PointerType(); 01975 invalidSchemaKeyword_ = 0; 01976 invalidDocumentPointer_ = PointerType(); 01977 } 01978 else { 01979 invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); 01980 invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); 01981 invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); 01982 } 01983 01984 return parseResult_; 01985 } 01986 01987 const ParseResult& GetParseResult() const { return parseResult_; } 01988 bool IsValid() const { return isValid_; } 01989 const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } 01990 const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } 01991 const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } 01992 01993 private: 01994 InputStream& is_; 01995 const SchemaDocumentType& sd_; 01996 01997 ParseResult parseResult_; 01998 PointerType invalidSchemaPointer_; 01999 const Ch* invalidSchemaKeyword_; 02000 PointerType invalidDocumentPointer_; 02001 bool isValid_; 02002 }; 02003 02004 RAPIDJSON_NAMESPACE_END 02005 RAPIDJSON_DIAG_POP 02006 02007 #endif // RAPIDJSON_SCHEMA_H_
Generated on Tue Jul 12 2022 12:06:49 by 1.7.2