DeepCover Embedded Security in IoT: Public-key Secured Data Paths

Dependencies:   MaximInterface

The MAXREFDES155# is an internet-of-things (IoT) embedded-security reference design, built to authenticate and control a sensing node using elliptic-curve-based public-key cryptography with control and notification from a web server.

The hardware includes an ARM® mbed™ shield and attached sensor endpoint. The shield contains a DS2476 DeepCover® ECDSA/SHA-2 coprocessor, Wifi communication, LCD push-button controls, and status LEDs. The sensor endpoint is attached to the shield using a 300mm cable and contains a DS28C36 DeepCover ECDSA/SHA-2 authenticator, IR-thermal sensor, and aiming laser for the IR sensor. The MAXREFDES155# is equipped with a standard Arduino® form-factor shield connector for immediate testing using an mbed board such as the MAX32600MBED#. The combination of these two devices represent an IoT device. Communication to the web server is accomplished with the shield Wifi circuitry. Communication from the shield to the attached sensor module is accomplished over I2C . The sensor module represents an IoT endpoint that generates small data with a requirement for message authenticity/integrity and secure on/off operational control.

The design is hierarchical with each mbed platform and shield communicating data from the sensor node to a web server that maintains a centralized log and dispatches notifications as necessary. The simplicity of this design enables rapid integration into any star-topology IoT network to provide security with the low overhead and cost provided by the ECDSA-P256 asymmetric-key and SHA-256 symmetric-key algorithms.

More information about the MAXREFDES155# is available on the Maxim Integrated website.

Committer:
IanBenzMaxim
Date:
Fri Jan 19 10:28:27 2018 -0600
Revision:
15:75404fab3615
Parent:
0:33d4e66780c0
Updated MaximInterface revision.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
IanBenzMaxim 0:33d4e66780c0 1 // Tencent is pleased to support the open source community by making RapidJSON available->
IanBenzMaxim 0:33d4e66780c0 2 //
IanBenzMaxim 0:33d4e66780c0 3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
IanBenzMaxim 0:33d4e66780c0 4 //
IanBenzMaxim 0:33d4e66780c0 5 // Licensed under the MIT License (the "License"); you may not use this file except
IanBenzMaxim 0:33d4e66780c0 6 // in compliance with the License-> You may obtain a copy of the License at
IanBenzMaxim 0:33d4e66780c0 7 //
IanBenzMaxim 0:33d4e66780c0 8 // http://opensource->org/licenses/MIT
IanBenzMaxim 0:33d4e66780c0 9 //
IanBenzMaxim 0:33d4e66780c0 10 // Unless required by applicable law or agreed to in writing, software distributed
IanBenzMaxim 0:33d4e66780c0 11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
IanBenzMaxim 0:33d4e66780c0 12 // CONDITIONS OF ANY KIND, either express or implied-> See the License for the
IanBenzMaxim 0:33d4e66780c0 13 // specific language governing permissions and limitations under the License->
IanBenzMaxim 0:33d4e66780c0 14
IanBenzMaxim 0:33d4e66780c0 15 #ifndef RAPIDJSON_SCHEMA_H_
IanBenzMaxim 0:33d4e66780c0 16 #define RAPIDJSON_SCHEMA_H_
IanBenzMaxim 0:33d4e66780c0 17
IanBenzMaxim 0:33d4e66780c0 18 #include "document.h"
IanBenzMaxim 0:33d4e66780c0 19 #include "pointer.h"
IanBenzMaxim 0:33d4e66780c0 20 #include <cmath> // abs, floor
IanBenzMaxim 0:33d4e66780c0 21
IanBenzMaxim 0:33d4e66780c0 22 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
IanBenzMaxim 0:33d4e66780c0 23 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
IanBenzMaxim 0:33d4e66780c0 24 #else
IanBenzMaxim 0:33d4e66780c0 25 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
IanBenzMaxim 0:33d4e66780c0 26 #endif
IanBenzMaxim 0:33d4e66780c0 27
IanBenzMaxim 0:33d4e66780c0 28 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
IanBenzMaxim 0:33d4e66780c0 29 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1
IanBenzMaxim 0:33d4e66780c0 30 #else
IanBenzMaxim 0:33d4e66780c0 31 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
IanBenzMaxim 0:33d4e66780c0 32 #endif
IanBenzMaxim 0:33d4e66780c0 33
IanBenzMaxim 0:33d4e66780c0 34 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
IanBenzMaxim 0:33d4e66780c0 35 #include "internal/regex.h"
IanBenzMaxim 0:33d4e66780c0 36 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
IanBenzMaxim 0:33d4e66780c0 37 #include <regex>
IanBenzMaxim 0:33d4e66780c0 38 #endif
IanBenzMaxim 0:33d4e66780c0 39
IanBenzMaxim 0:33d4e66780c0 40 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
IanBenzMaxim 0:33d4e66780c0 41 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
IanBenzMaxim 0:33d4e66780c0 42 #else
IanBenzMaxim 0:33d4e66780c0 43 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
IanBenzMaxim 0:33d4e66780c0 44 #endif
IanBenzMaxim 0:33d4e66780c0 45
IanBenzMaxim 0:33d4e66780c0 46 #ifndef RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 47 #define RAPIDJSON_SCHEMA_VERBOSE 0
IanBenzMaxim 0:33d4e66780c0 48 #endif
IanBenzMaxim 0:33d4e66780c0 49
IanBenzMaxim 0:33d4e66780c0 50 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 51 #include "stringbuffer.h"
IanBenzMaxim 0:33d4e66780c0 52 #endif
IanBenzMaxim 0:33d4e66780c0 53
IanBenzMaxim 0:33d4e66780c0 54 RAPIDJSON_DIAG_PUSH
IanBenzMaxim 0:33d4e66780c0 55
IanBenzMaxim 0:33d4e66780c0 56 #if defined(__GNUC__)
IanBenzMaxim 0:33d4e66780c0 57 RAPIDJSON_DIAG_OFF(effc++)
IanBenzMaxim 0:33d4e66780c0 58 #endif
IanBenzMaxim 0:33d4e66780c0 59
IanBenzMaxim 0:33d4e66780c0 60 #ifdef __clang__
IanBenzMaxim 0:33d4e66780c0 61 RAPIDJSON_DIAG_OFF(weak-vtables)
IanBenzMaxim 0:33d4e66780c0 62 RAPIDJSON_DIAG_OFF(exit-time-destructors)
IanBenzMaxim 0:33d4e66780c0 63 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
IanBenzMaxim 0:33d4e66780c0 64 RAPIDJSON_DIAG_OFF(variadic-macros)
IanBenzMaxim 0:33d4e66780c0 65 #endif
IanBenzMaxim 0:33d4e66780c0 66
IanBenzMaxim 0:33d4e66780c0 67 #ifdef _MSC_VER
IanBenzMaxim 0:33d4e66780c0 68 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
IanBenzMaxim 0:33d4e66780c0 69 #endif
IanBenzMaxim 0:33d4e66780c0 70
IanBenzMaxim 0:33d4e66780c0 71 RAPIDJSON_NAMESPACE_BEGIN
IanBenzMaxim 0:33d4e66780c0 72
IanBenzMaxim 0:33d4e66780c0 73 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 74 // Verbose Utilities
IanBenzMaxim 0:33d4e66780c0 75
IanBenzMaxim 0:33d4e66780c0 76 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 77
IanBenzMaxim 0:33d4e66780c0 78 namespace internal {
IanBenzMaxim 0:33d4e66780c0 79
IanBenzMaxim 0:33d4e66780c0 80 inline void PrintInvalidKeyword(const char* keyword) {
IanBenzMaxim 0:33d4e66780c0 81 printf("Fail keyword: %s\n", keyword);
IanBenzMaxim 0:33d4e66780c0 82 }
IanBenzMaxim 0:33d4e66780c0 83
IanBenzMaxim 0:33d4e66780c0 84 inline void PrintInvalidKeyword(const wchar_t* keyword) {
IanBenzMaxim 0:33d4e66780c0 85 wprintf(L"Fail keyword: %ls\n", keyword);
IanBenzMaxim 0:33d4e66780c0 86 }
IanBenzMaxim 0:33d4e66780c0 87
IanBenzMaxim 0:33d4e66780c0 88 inline void PrintInvalidDocument(const char* document) {
IanBenzMaxim 0:33d4e66780c0 89 printf("Fail document: %s\n\n", document);
IanBenzMaxim 0:33d4e66780c0 90 }
IanBenzMaxim 0:33d4e66780c0 91
IanBenzMaxim 0:33d4e66780c0 92 inline void PrintInvalidDocument(const wchar_t* document) {
IanBenzMaxim 0:33d4e66780c0 93 wprintf(L"Fail document: %ls\n\n", document);
IanBenzMaxim 0:33d4e66780c0 94 }
IanBenzMaxim 0:33d4e66780c0 95
IanBenzMaxim 0:33d4e66780c0 96 inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
IanBenzMaxim 0:33d4e66780c0 97 printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
IanBenzMaxim 0:33d4e66780c0 98 }
IanBenzMaxim 0:33d4e66780c0 99
IanBenzMaxim 0:33d4e66780c0 100 inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
IanBenzMaxim 0:33d4e66780c0 101 wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
IanBenzMaxim 0:33d4e66780c0 102 }
IanBenzMaxim 0:33d4e66780c0 103
IanBenzMaxim 0:33d4e66780c0 104 } // namespace internal
IanBenzMaxim 0:33d4e66780c0 105
IanBenzMaxim 0:33d4e66780c0 106 #endif // RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 107
IanBenzMaxim 0:33d4e66780c0 108 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 109 // RAPIDJSON_INVALID_KEYWORD_RETURN
IanBenzMaxim 0:33d4e66780c0 110
IanBenzMaxim 0:33d4e66780c0 111 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 112 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
IanBenzMaxim 0:33d4e66780c0 113 #else
IanBenzMaxim 0:33d4e66780c0 114 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
IanBenzMaxim 0:33d4e66780c0 115 #endif
IanBenzMaxim 0:33d4e66780c0 116
IanBenzMaxim 0:33d4e66780c0 117 #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
IanBenzMaxim 0:33d4e66780c0 118 RAPIDJSON_MULTILINEMACRO_BEGIN\
IanBenzMaxim 0:33d4e66780c0 119 context.invalidKeyword = keyword.GetString();\
IanBenzMaxim 0:33d4e66780c0 120 RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
IanBenzMaxim 0:33d4e66780c0 121 return false;\
IanBenzMaxim 0:33d4e66780c0 122 RAPIDJSON_MULTILINEMACRO_END
IanBenzMaxim 0:33d4e66780c0 123
IanBenzMaxim 0:33d4e66780c0 124 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 125 // Forward declarations
IanBenzMaxim 0:33d4e66780c0 126
IanBenzMaxim 0:33d4e66780c0 127 template <typename ValueType, typename Allocator>
IanBenzMaxim 0:33d4e66780c0 128 class GenericSchemaDocument;
IanBenzMaxim 0:33d4e66780c0 129
IanBenzMaxim 0:33d4e66780c0 130 namespace internal {
IanBenzMaxim 0:33d4e66780c0 131
IanBenzMaxim 0:33d4e66780c0 132 template <typename SchemaDocumentType>
IanBenzMaxim 0:33d4e66780c0 133 class Schema;
IanBenzMaxim 0:33d4e66780c0 134
IanBenzMaxim 0:33d4e66780c0 135 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 136 // ISchemaValidator
IanBenzMaxim 0:33d4e66780c0 137
IanBenzMaxim 0:33d4e66780c0 138 class ISchemaValidator {
IanBenzMaxim 0:33d4e66780c0 139 public:
IanBenzMaxim 0:33d4e66780c0 140 virtual ~ISchemaValidator() {}
IanBenzMaxim 0:33d4e66780c0 141 virtual bool IsValid() const = 0;
IanBenzMaxim 0:33d4e66780c0 142 };
IanBenzMaxim 0:33d4e66780c0 143
IanBenzMaxim 0:33d4e66780c0 144 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 145 // ISchemaStateFactory
IanBenzMaxim 0:33d4e66780c0 146
IanBenzMaxim 0:33d4e66780c0 147 template <typename SchemaType>
IanBenzMaxim 0:33d4e66780c0 148 class ISchemaStateFactory {
IanBenzMaxim 0:33d4e66780c0 149 public:
IanBenzMaxim 0:33d4e66780c0 150 virtual ~ISchemaStateFactory() {}
IanBenzMaxim 0:33d4e66780c0 151 virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
IanBenzMaxim 0:33d4e66780c0 152 virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
IanBenzMaxim 0:33d4e66780c0 153 virtual void* CreateHasher() = 0;
IanBenzMaxim 0:33d4e66780c0 154 virtual uint64_t GetHashCode(void* hasher) = 0;
IanBenzMaxim 0:33d4e66780c0 155 virtual void DestroryHasher(void* hasher) = 0;
IanBenzMaxim 0:33d4e66780c0 156 virtual void* MallocState(size_t size) = 0;
IanBenzMaxim 0:33d4e66780c0 157 virtual void FreeState(void* p) = 0;
IanBenzMaxim 0:33d4e66780c0 158 };
IanBenzMaxim 0:33d4e66780c0 159
IanBenzMaxim 0:33d4e66780c0 160 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 161 // Hasher
IanBenzMaxim 0:33d4e66780c0 162
IanBenzMaxim 0:33d4e66780c0 163 // For comparison of compound value
IanBenzMaxim 0:33d4e66780c0 164 template<typename Encoding, typename Allocator>
IanBenzMaxim 0:33d4e66780c0 165 class Hasher {
IanBenzMaxim 0:33d4e66780c0 166 public:
IanBenzMaxim 0:33d4e66780c0 167 typedef typename Encoding::Ch Ch;
IanBenzMaxim 0:33d4e66780c0 168
IanBenzMaxim 0:33d4e66780c0 169 Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
IanBenzMaxim 0:33d4e66780c0 170
IanBenzMaxim 0:33d4e66780c0 171 bool Null() { return WriteType(kNullType); }
IanBenzMaxim 0:33d4e66780c0 172 bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
IanBenzMaxim 0:33d4e66780c0 173 bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
IanBenzMaxim 0:33d4e66780c0 174 bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
IanBenzMaxim 0:33d4e66780c0 175 bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
IanBenzMaxim 0:33d4e66780c0 176 bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
IanBenzMaxim 0:33d4e66780c0 177 bool Double(double d) {
IanBenzMaxim 0:33d4e66780c0 178 Number n;
IanBenzMaxim 0:33d4e66780c0 179 if (d < 0) n.u.i = static_cast<int64_t>(d);
IanBenzMaxim 0:33d4e66780c0 180 else n.u.u = static_cast<uint64_t>(d);
IanBenzMaxim 0:33d4e66780c0 181 n.d = d;
IanBenzMaxim 0:33d4e66780c0 182 return WriteNumber(n);
IanBenzMaxim 0:33d4e66780c0 183 }
IanBenzMaxim 0:33d4e66780c0 184
IanBenzMaxim 0:33d4e66780c0 185 bool RawNumber(const Ch* str, SizeType len, bool) {
IanBenzMaxim 0:33d4e66780c0 186 WriteBuffer(kNumberType, str, len * sizeof(Ch));
IanBenzMaxim 0:33d4e66780c0 187 return true;
IanBenzMaxim 0:33d4e66780c0 188 }
IanBenzMaxim 0:33d4e66780c0 189
IanBenzMaxim 0:33d4e66780c0 190 bool String(const Ch* str, SizeType len, bool) {
IanBenzMaxim 0:33d4e66780c0 191 WriteBuffer(kStringType, str, len * sizeof(Ch));
IanBenzMaxim 0:33d4e66780c0 192 return true;
IanBenzMaxim 0:33d4e66780c0 193 }
IanBenzMaxim 0:33d4e66780c0 194
IanBenzMaxim 0:33d4e66780c0 195 bool StartObject() { return true; }
IanBenzMaxim 0:33d4e66780c0 196 bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
IanBenzMaxim 0:33d4e66780c0 197 bool EndObject(SizeType memberCount) {
IanBenzMaxim 0:33d4e66780c0 198 uint64_t h = Hash(0, kObjectType);
IanBenzMaxim 0:33d4e66780c0 199 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
IanBenzMaxim 0:33d4e66780c0 200 for (SizeType i = 0; i < memberCount; i++)
IanBenzMaxim 0:33d4e66780c0 201 h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive
IanBenzMaxim 0:33d4e66780c0 202 *stack_.template Push<uint64_t>() = h;
IanBenzMaxim 0:33d4e66780c0 203 return true;
IanBenzMaxim 0:33d4e66780c0 204 }
IanBenzMaxim 0:33d4e66780c0 205
IanBenzMaxim 0:33d4e66780c0 206 bool StartArray() { return true; }
IanBenzMaxim 0:33d4e66780c0 207 bool EndArray(SizeType elementCount) {
IanBenzMaxim 0:33d4e66780c0 208 uint64_t h = Hash(0, kArrayType);
IanBenzMaxim 0:33d4e66780c0 209 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
IanBenzMaxim 0:33d4e66780c0 210 for (SizeType i = 0; i < elementCount; i++)
IanBenzMaxim 0:33d4e66780c0 211 h = Hash(h, e[i]); // Use hash to achieve element order sensitive
IanBenzMaxim 0:33d4e66780c0 212 *stack_.template Push<uint64_t>() = h;
IanBenzMaxim 0:33d4e66780c0 213 return true;
IanBenzMaxim 0:33d4e66780c0 214 }
IanBenzMaxim 0:33d4e66780c0 215
IanBenzMaxim 0:33d4e66780c0 216 bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
IanBenzMaxim 0:33d4e66780c0 217
IanBenzMaxim 0:33d4e66780c0 218 uint64_t GetHashCode() const {
IanBenzMaxim 0:33d4e66780c0 219 RAPIDJSON_ASSERT(IsValid());
IanBenzMaxim 0:33d4e66780c0 220 return *stack_.template Top<uint64_t>();
IanBenzMaxim 0:33d4e66780c0 221 }
IanBenzMaxim 0:33d4e66780c0 222
IanBenzMaxim 0:33d4e66780c0 223 private:
IanBenzMaxim 0:33d4e66780c0 224 static const size_t kDefaultSize = 256;
IanBenzMaxim 0:33d4e66780c0 225 struct Number {
IanBenzMaxim 0:33d4e66780c0 226 union U {
IanBenzMaxim 0:33d4e66780c0 227 uint64_t u;
IanBenzMaxim 0:33d4e66780c0 228 int64_t i;
IanBenzMaxim 0:33d4e66780c0 229 }u;
IanBenzMaxim 0:33d4e66780c0 230 double d;
IanBenzMaxim 0:33d4e66780c0 231 };
IanBenzMaxim 0:33d4e66780c0 232
IanBenzMaxim 0:33d4e66780c0 233 bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
IanBenzMaxim 0:33d4e66780c0 234
IanBenzMaxim 0:33d4e66780c0 235 bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
IanBenzMaxim 0:33d4e66780c0 236
IanBenzMaxim 0:33d4e66780c0 237 bool WriteBuffer(Type type, const void* data, size_t len) {
IanBenzMaxim 0:33d4e66780c0 238 // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
IanBenzMaxim 0:33d4e66780c0 239 uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
IanBenzMaxim 0:33d4e66780c0 240 const unsigned char* d = static_cast<const unsigned char*>(data);
IanBenzMaxim 0:33d4e66780c0 241 for (size_t i = 0; i < len; i++)
IanBenzMaxim 0:33d4e66780c0 242 h = Hash(h, d[i]);
IanBenzMaxim 0:33d4e66780c0 243 *stack_.template Push<uint64_t>() = h;
IanBenzMaxim 0:33d4e66780c0 244 return true;
IanBenzMaxim 0:33d4e66780c0 245 }
IanBenzMaxim 0:33d4e66780c0 246
IanBenzMaxim 0:33d4e66780c0 247 static uint64_t Hash(uint64_t h, uint64_t d) {
IanBenzMaxim 0:33d4e66780c0 248 static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
IanBenzMaxim 0:33d4e66780c0 249 h ^= d;
IanBenzMaxim 0:33d4e66780c0 250 h *= kPrime;
IanBenzMaxim 0:33d4e66780c0 251 return h;
IanBenzMaxim 0:33d4e66780c0 252 }
IanBenzMaxim 0:33d4e66780c0 253
IanBenzMaxim 0:33d4e66780c0 254 Stack<Allocator> stack_;
IanBenzMaxim 0:33d4e66780c0 255 };
IanBenzMaxim 0:33d4e66780c0 256
IanBenzMaxim 0:33d4e66780c0 257 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 258 // SchemaValidationContext
IanBenzMaxim 0:33d4e66780c0 259
IanBenzMaxim 0:33d4e66780c0 260 template <typename SchemaDocumentType>
IanBenzMaxim 0:33d4e66780c0 261 struct SchemaValidationContext {
IanBenzMaxim 0:33d4e66780c0 262 typedef Schema<SchemaDocumentType> SchemaType;
IanBenzMaxim 0:33d4e66780c0 263 typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
IanBenzMaxim 0:33d4e66780c0 264 typedef typename SchemaType::ValueType ValueType;
IanBenzMaxim 0:33d4e66780c0 265 typedef typename ValueType::Ch Ch;
IanBenzMaxim 0:33d4e66780c0 266
IanBenzMaxim 0:33d4e66780c0 267 enum PatternValidatorType {
IanBenzMaxim 0:33d4e66780c0 268 kPatternValidatorOnly,
IanBenzMaxim 0:33d4e66780c0 269 kPatternValidatorWithProperty,
IanBenzMaxim 0:33d4e66780c0 270 kPatternValidatorWithAdditionalProperty
IanBenzMaxim 0:33d4e66780c0 271 };
IanBenzMaxim 0:33d4e66780c0 272
IanBenzMaxim 0:33d4e66780c0 273 SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
IanBenzMaxim 0:33d4e66780c0 274 factory(f),
IanBenzMaxim 0:33d4e66780c0 275 schema(s),
IanBenzMaxim 0:33d4e66780c0 276 valueSchema(),
IanBenzMaxim 0:33d4e66780c0 277 invalidKeyword(),
IanBenzMaxim 0:33d4e66780c0 278 hasher(),
IanBenzMaxim 0:33d4e66780c0 279 arrayElementHashCodes(),
IanBenzMaxim 0:33d4e66780c0 280 validators(),
IanBenzMaxim 0:33d4e66780c0 281 validatorCount(),
IanBenzMaxim 0:33d4e66780c0 282 patternPropertiesValidators(),
IanBenzMaxim 0:33d4e66780c0 283 patternPropertiesValidatorCount(),
IanBenzMaxim 0:33d4e66780c0 284 patternPropertiesSchemas(),
IanBenzMaxim 0:33d4e66780c0 285 patternPropertiesSchemaCount(),
IanBenzMaxim 0:33d4e66780c0 286 valuePatternValidatorType(kPatternValidatorOnly),
IanBenzMaxim 0:33d4e66780c0 287 propertyExist(),
IanBenzMaxim 0:33d4e66780c0 288 inArray(false),
IanBenzMaxim 0:33d4e66780c0 289 valueUniqueness(false),
IanBenzMaxim 0:33d4e66780c0 290 arrayUniqueness(false)
IanBenzMaxim 0:33d4e66780c0 291 {
IanBenzMaxim 0:33d4e66780c0 292 }
IanBenzMaxim 0:33d4e66780c0 293
IanBenzMaxim 0:33d4e66780c0 294 ~SchemaValidationContext() {
IanBenzMaxim 0:33d4e66780c0 295 if (hasher)
IanBenzMaxim 0:33d4e66780c0 296 factory.DestroryHasher(hasher);
IanBenzMaxim 0:33d4e66780c0 297 if (validators) {
IanBenzMaxim 0:33d4e66780c0 298 for (SizeType i = 0; i < validatorCount; i++)
IanBenzMaxim 0:33d4e66780c0 299 factory.DestroySchemaValidator(validators[i]);
IanBenzMaxim 0:33d4e66780c0 300 factory.FreeState(validators);
IanBenzMaxim 0:33d4e66780c0 301 }
IanBenzMaxim 0:33d4e66780c0 302 if (patternPropertiesValidators) {
IanBenzMaxim 0:33d4e66780c0 303 for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
IanBenzMaxim 0:33d4e66780c0 304 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
IanBenzMaxim 0:33d4e66780c0 305 factory.FreeState(patternPropertiesValidators);
IanBenzMaxim 0:33d4e66780c0 306 }
IanBenzMaxim 0:33d4e66780c0 307 if (patternPropertiesSchemas)
IanBenzMaxim 0:33d4e66780c0 308 factory.FreeState(patternPropertiesSchemas);
IanBenzMaxim 0:33d4e66780c0 309 if (propertyExist)
IanBenzMaxim 0:33d4e66780c0 310 factory.FreeState(propertyExist);
IanBenzMaxim 0:33d4e66780c0 311 }
IanBenzMaxim 0:33d4e66780c0 312
IanBenzMaxim 0:33d4e66780c0 313 SchemaValidatorFactoryType& factory;
IanBenzMaxim 0:33d4e66780c0 314 const SchemaType* schema;
IanBenzMaxim 0:33d4e66780c0 315 const SchemaType* valueSchema;
IanBenzMaxim 0:33d4e66780c0 316 const Ch* invalidKeyword;
IanBenzMaxim 0:33d4e66780c0 317 void* hasher; // Only validator access
IanBenzMaxim 0:33d4e66780c0 318 void* arrayElementHashCodes; // Only validator access this
IanBenzMaxim 0:33d4e66780c0 319 ISchemaValidator** validators;
IanBenzMaxim 0:33d4e66780c0 320 SizeType validatorCount;
IanBenzMaxim 0:33d4e66780c0 321 ISchemaValidator** patternPropertiesValidators;
IanBenzMaxim 0:33d4e66780c0 322 SizeType patternPropertiesValidatorCount;
IanBenzMaxim 0:33d4e66780c0 323 const SchemaType** patternPropertiesSchemas;
IanBenzMaxim 0:33d4e66780c0 324 SizeType patternPropertiesSchemaCount;
IanBenzMaxim 0:33d4e66780c0 325 PatternValidatorType valuePatternValidatorType;
IanBenzMaxim 0:33d4e66780c0 326 PatternValidatorType objectPatternValidatorType;
IanBenzMaxim 0:33d4e66780c0 327 SizeType arrayElementIndex;
IanBenzMaxim 0:33d4e66780c0 328 bool* propertyExist;
IanBenzMaxim 0:33d4e66780c0 329 bool inArray;
IanBenzMaxim 0:33d4e66780c0 330 bool valueUniqueness;
IanBenzMaxim 0:33d4e66780c0 331 bool arrayUniqueness;
IanBenzMaxim 0:33d4e66780c0 332 };
IanBenzMaxim 0:33d4e66780c0 333
IanBenzMaxim 0:33d4e66780c0 334 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 335 // Schema
IanBenzMaxim 0:33d4e66780c0 336
IanBenzMaxim 0:33d4e66780c0 337 template <typename SchemaDocumentType>
IanBenzMaxim 0:33d4e66780c0 338 class Schema {
IanBenzMaxim 0:33d4e66780c0 339 public:
IanBenzMaxim 0:33d4e66780c0 340 typedef typename SchemaDocumentType::ValueType ValueType;
IanBenzMaxim 0:33d4e66780c0 341 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
IanBenzMaxim 0:33d4e66780c0 342 typedef typename SchemaDocumentType::PointerType PointerType;
IanBenzMaxim 0:33d4e66780c0 343 typedef typename ValueType::EncodingType EncodingType;
IanBenzMaxim 0:33d4e66780c0 344 typedef typename EncodingType::Ch Ch;
IanBenzMaxim 0:33d4e66780c0 345 typedef SchemaValidationContext<SchemaDocumentType> Context;
IanBenzMaxim 0:33d4e66780c0 346 typedef Schema<SchemaDocumentType> SchemaType;
IanBenzMaxim 0:33d4e66780c0 347 typedef GenericValue<EncodingType, AllocatorType> SValue;
IanBenzMaxim 0:33d4e66780c0 348 friend class GenericSchemaDocument<ValueType, AllocatorType>;
IanBenzMaxim 0:33d4e66780c0 349
IanBenzMaxim 0:33d4e66780c0 350 Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
IanBenzMaxim 0:33d4e66780c0 351 allocator_(allocator),
IanBenzMaxim 0:33d4e66780c0 352 enum_(),
IanBenzMaxim 0:33d4e66780c0 353 enumCount_(),
IanBenzMaxim 0:33d4e66780c0 354 not_(),
IanBenzMaxim 0:33d4e66780c0 355 type_((1 << kTotalSchemaType) - 1), // typeless
IanBenzMaxim 0:33d4e66780c0 356 validatorCount_(),
IanBenzMaxim 0:33d4e66780c0 357 properties_(),
IanBenzMaxim 0:33d4e66780c0 358 additionalPropertiesSchema_(),
IanBenzMaxim 0:33d4e66780c0 359 patternProperties_(),
IanBenzMaxim 0:33d4e66780c0 360 patternPropertyCount_(),
IanBenzMaxim 0:33d4e66780c0 361 propertyCount_(),
IanBenzMaxim 0:33d4e66780c0 362 minProperties_(),
IanBenzMaxim 0:33d4e66780c0 363 maxProperties_(SizeType(~0)),
IanBenzMaxim 0:33d4e66780c0 364 additionalProperties_(true),
IanBenzMaxim 0:33d4e66780c0 365 hasDependencies_(),
IanBenzMaxim 0:33d4e66780c0 366 hasRequired_(),
IanBenzMaxim 0:33d4e66780c0 367 hasSchemaDependencies_(),
IanBenzMaxim 0:33d4e66780c0 368 additionalItemsSchema_(),
IanBenzMaxim 0:33d4e66780c0 369 itemsList_(),
IanBenzMaxim 0:33d4e66780c0 370 itemsTuple_(),
IanBenzMaxim 0:33d4e66780c0 371 itemsTupleCount_(),
IanBenzMaxim 0:33d4e66780c0 372 minItems_(),
IanBenzMaxim 0:33d4e66780c0 373 maxItems_(SizeType(~0)),
IanBenzMaxim 0:33d4e66780c0 374 additionalItems_(true),
IanBenzMaxim 0:33d4e66780c0 375 uniqueItems_(false),
IanBenzMaxim 0:33d4e66780c0 376 pattern_(),
IanBenzMaxim 0:33d4e66780c0 377 minLength_(0),
IanBenzMaxim 0:33d4e66780c0 378 maxLength_(~SizeType(0)),
IanBenzMaxim 0:33d4e66780c0 379 exclusiveMinimum_(false),
IanBenzMaxim 0:33d4e66780c0 380 exclusiveMaximum_(false)
IanBenzMaxim 0:33d4e66780c0 381 {
IanBenzMaxim 0:33d4e66780c0 382 typedef typename SchemaDocumentType::ValueType ValueType;
IanBenzMaxim 0:33d4e66780c0 383 typedef typename ValueType::ConstValueIterator ConstValueIterator;
IanBenzMaxim 0:33d4e66780c0 384 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
IanBenzMaxim 0:33d4e66780c0 385
IanBenzMaxim 0:33d4e66780c0 386 if (!value.IsObject())
IanBenzMaxim 0:33d4e66780c0 387 return;
IanBenzMaxim 0:33d4e66780c0 388
IanBenzMaxim 0:33d4e66780c0 389 if (const ValueType* v = GetMember(value, GetTypeString())) {
IanBenzMaxim 0:33d4e66780c0 390 type_ = 0;
IanBenzMaxim 0:33d4e66780c0 391 if (v->IsString())
IanBenzMaxim 0:33d4e66780c0 392 AddType(*v);
IanBenzMaxim 0:33d4e66780c0 393 else if (v->IsArray())
IanBenzMaxim 0:33d4e66780c0 394 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
IanBenzMaxim 0:33d4e66780c0 395 AddType(*itr);
IanBenzMaxim 0:33d4e66780c0 396 }
IanBenzMaxim 0:33d4e66780c0 397
IanBenzMaxim 0:33d4e66780c0 398 if (const ValueType* v = GetMember(value, GetEnumString()))
IanBenzMaxim 0:33d4e66780c0 399 if (v->IsArray() && v->Size() > 0) {
IanBenzMaxim 0:33d4e66780c0 400 enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
IanBenzMaxim 0:33d4e66780c0 401 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
IanBenzMaxim 0:33d4e66780c0 402 typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
IanBenzMaxim 0:33d4e66780c0 403 char buffer[256 + 24];
IanBenzMaxim 0:33d4e66780c0 404 MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
IanBenzMaxim 0:33d4e66780c0 405 EnumHasherType h(&hasherAllocator, 256);
IanBenzMaxim 0:33d4e66780c0 406 itr->Accept(h);
IanBenzMaxim 0:33d4e66780c0 407 enum_[enumCount_++] = h.GetHashCode();
IanBenzMaxim 0:33d4e66780c0 408 }
IanBenzMaxim 0:33d4e66780c0 409 }
IanBenzMaxim 0:33d4e66780c0 410
IanBenzMaxim 0:33d4e66780c0 411 if (schemaDocument) {
IanBenzMaxim 0:33d4e66780c0 412 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
IanBenzMaxim 0:33d4e66780c0 413 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
IanBenzMaxim 0:33d4e66780c0 414 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
IanBenzMaxim 0:33d4e66780c0 415 }
IanBenzMaxim 0:33d4e66780c0 416
IanBenzMaxim 0:33d4e66780c0 417 if (const ValueType* v = GetMember(value, GetNotString())) {
IanBenzMaxim 0:33d4e66780c0 418 schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
IanBenzMaxim 0:33d4e66780c0 419 notValidatorIndex_ = validatorCount_;
IanBenzMaxim 0:33d4e66780c0 420 validatorCount_++;
IanBenzMaxim 0:33d4e66780c0 421 }
IanBenzMaxim 0:33d4e66780c0 422
IanBenzMaxim 0:33d4e66780c0 423 // Object
IanBenzMaxim 0:33d4e66780c0 424
IanBenzMaxim 0:33d4e66780c0 425 const ValueType* properties = GetMember(value, GetPropertiesString());
IanBenzMaxim 0:33d4e66780c0 426 const ValueType* required = GetMember(value, GetRequiredString());
IanBenzMaxim 0:33d4e66780c0 427 const ValueType* dependencies = GetMember(value, GetDependenciesString());
IanBenzMaxim 0:33d4e66780c0 428 {
IanBenzMaxim 0:33d4e66780c0 429 // Gather properties from properties/required/dependencies
IanBenzMaxim 0:33d4e66780c0 430 SValue allProperties(kArrayType);
IanBenzMaxim 0:33d4e66780c0 431
IanBenzMaxim 0:33d4e66780c0 432 if (properties && properties->IsObject())
IanBenzMaxim 0:33d4e66780c0 433 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
IanBenzMaxim 0:33d4e66780c0 434 AddUniqueElement(allProperties, itr->name);
IanBenzMaxim 0:33d4e66780c0 435
IanBenzMaxim 0:33d4e66780c0 436 if (required && required->IsArray())
IanBenzMaxim 0:33d4e66780c0 437 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
IanBenzMaxim 0:33d4e66780c0 438 if (itr->IsString())
IanBenzMaxim 0:33d4e66780c0 439 AddUniqueElement(allProperties, *itr);
IanBenzMaxim 0:33d4e66780c0 440
IanBenzMaxim 0:33d4e66780c0 441 if (dependencies && dependencies->IsObject())
IanBenzMaxim 0:33d4e66780c0 442 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
IanBenzMaxim 0:33d4e66780c0 443 AddUniqueElement(allProperties, itr->name);
IanBenzMaxim 0:33d4e66780c0 444 if (itr->value.IsArray())
IanBenzMaxim 0:33d4e66780c0 445 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
IanBenzMaxim 0:33d4e66780c0 446 if (i->IsString())
IanBenzMaxim 0:33d4e66780c0 447 AddUniqueElement(allProperties, *i);
IanBenzMaxim 0:33d4e66780c0 448 }
IanBenzMaxim 0:33d4e66780c0 449
IanBenzMaxim 0:33d4e66780c0 450 if (allProperties.Size() > 0) {
IanBenzMaxim 0:33d4e66780c0 451 propertyCount_ = allProperties.Size();
IanBenzMaxim 0:33d4e66780c0 452 properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
IanBenzMaxim 0:33d4e66780c0 453 for (SizeType i = 0; i < propertyCount_; i++) {
IanBenzMaxim 0:33d4e66780c0 454 new (&properties_[i]) Property();
IanBenzMaxim 0:33d4e66780c0 455 properties_[i].name = allProperties[i];
IanBenzMaxim 0:33d4e66780c0 456 properties_[i].schema = GetTypeless();
IanBenzMaxim 0:33d4e66780c0 457 }
IanBenzMaxim 0:33d4e66780c0 458 }
IanBenzMaxim 0:33d4e66780c0 459 }
IanBenzMaxim 0:33d4e66780c0 460
IanBenzMaxim 0:33d4e66780c0 461 if (properties && properties->IsObject()) {
IanBenzMaxim 0:33d4e66780c0 462 PointerType q = p.Append(GetPropertiesString(), allocator_);
IanBenzMaxim 0:33d4e66780c0 463 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
IanBenzMaxim 0:33d4e66780c0 464 SizeType index;
IanBenzMaxim 0:33d4e66780c0 465 if (FindPropertyIndex(itr->name, &index))
IanBenzMaxim 0:33d4e66780c0 466 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
IanBenzMaxim 0:33d4e66780c0 467 }
IanBenzMaxim 0:33d4e66780c0 468 }
IanBenzMaxim 0:33d4e66780c0 469
IanBenzMaxim 0:33d4e66780c0 470 if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
IanBenzMaxim 0:33d4e66780c0 471 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
IanBenzMaxim 0:33d4e66780c0 472 patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
IanBenzMaxim 0:33d4e66780c0 473 patternPropertyCount_ = 0;
IanBenzMaxim 0:33d4e66780c0 474
IanBenzMaxim 0:33d4e66780c0 475 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
IanBenzMaxim 0:33d4e66780c0 476 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
IanBenzMaxim 0:33d4e66780c0 477 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
IanBenzMaxim 0:33d4e66780c0 478 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
IanBenzMaxim 0:33d4e66780c0 479 patternPropertyCount_++;
IanBenzMaxim 0:33d4e66780c0 480 }
IanBenzMaxim 0:33d4e66780c0 481 }
IanBenzMaxim 0:33d4e66780c0 482
IanBenzMaxim 0:33d4e66780c0 483 if (required && required->IsArray())
IanBenzMaxim 0:33d4e66780c0 484 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
IanBenzMaxim 0:33d4e66780c0 485 if (itr->IsString()) {
IanBenzMaxim 0:33d4e66780c0 486 SizeType index;
IanBenzMaxim 0:33d4e66780c0 487 if (FindPropertyIndex(*itr, &index)) {
IanBenzMaxim 0:33d4e66780c0 488 properties_[index].required = true;
IanBenzMaxim 0:33d4e66780c0 489 hasRequired_ = true;
IanBenzMaxim 0:33d4e66780c0 490 }
IanBenzMaxim 0:33d4e66780c0 491 }
IanBenzMaxim 0:33d4e66780c0 492
IanBenzMaxim 0:33d4e66780c0 493 if (dependencies && dependencies->IsObject()) {
IanBenzMaxim 0:33d4e66780c0 494 PointerType q = p.Append(GetDependenciesString(), allocator_);
IanBenzMaxim 0:33d4e66780c0 495 hasDependencies_ = true;
IanBenzMaxim 0:33d4e66780c0 496 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
IanBenzMaxim 0:33d4e66780c0 497 SizeType sourceIndex;
IanBenzMaxim 0:33d4e66780c0 498 if (FindPropertyIndex(itr->name, &sourceIndex)) {
IanBenzMaxim 0:33d4e66780c0 499 if (itr->value.IsArray()) {
IanBenzMaxim 0:33d4e66780c0 500 properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
IanBenzMaxim 0:33d4e66780c0 501 std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
IanBenzMaxim 0:33d4e66780c0 502 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
IanBenzMaxim 0:33d4e66780c0 503 SizeType targetIndex;
IanBenzMaxim 0:33d4e66780c0 504 if (FindPropertyIndex(*targetItr, &targetIndex))
IanBenzMaxim 0:33d4e66780c0 505 properties_[sourceIndex].dependencies[targetIndex] = true;
IanBenzMaxim 0:33d4e66780c0 506 }
IanBenzMaxim 0:33d4e66780c0 507 }
IanBenzMaxim 0:33d4e66780c0 508 else if (itr->value.IsObject()) {
IanBenzMaxim 0:33d4e66780c0 509 hasSchemaDependencies_ = true;
IanBenzMaxim 0:33d4e66780c0 510 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
IanBenzMaxim 0:33d4e66780c0 511 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
IanBenzMaxim 0:33d4e66780c0 512 validatorCount_++;
IanBenzMaxim 0:33d4e66780c0 513 }
IanBenzMaxim 0:33d4e66780c0 514 }
IanBenzMaxim 0:33d4e66780c0 515 }
IanBenzMaxim 0:33d4e66780c0 516 }
IanBenzMaxim 0:33d4e66780c0 517
IanBenzMaxim 0:33d4e66780c0 518 if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
IanBenzMaxim 0:33d4e66780c0 519 if (v->IsBool())
IanBenzMaxim 0:33d4e66780c0 520 additionalProperties_ = v->GetBool();
IanBenzMaxim 0:33d4e66780c0 521 else if (v->IsObject())
IanBenzMaxim 0:33d4e66780c0 522 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
IanBenzMaxim 0:33d4e66780c0 523 }
IanBenzMaxim 0:33d4e66780c0 524
IanBenzMaxim 0:33d4e66780c0 525 AssignIfExist(minProperties_, value, GetMinPropertiesString());
IanBenzMaxim 0:33d4e66780c0 526 AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
IanBenzMaxim 0:33d4e66780c0 527
IanBenzMaxim 0:33d4e66780c0 528 // Array
IanBenzMaxim 0:33d4e66780c0 529 if (const ValueType* v = GetMember(value, GetItemsString())) {
IanBenzMaxim 0:33d4e66780c0 530 PointerType q = p.Append(GetItemsString(), allocator_);
IanBenzMaxim 0:33d4e66780c0 531 if (v->IsObject()) // List validation
IanBenzMaxim 0:33d4e66780c0 532 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
IanBenzMaxim 0:33d4e66780c0 533 else if (v->IsArray()) { // Tuple validation
IanBenzMaxim 0:33d4e66780c0 534 itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
IanBenzMaxim 0:33d4e66780c0 535 SizeType index = 0;
IanBenzMaxim 0:33d4e66780c0 536 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
IanBenzMaxim 0:33d4e66780c0 537 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
IanBenzMaxim 0:33d4e66780c0 538 }
IanBenzMaxim 0:33d4e66780c0 539 }
IanBenzMaxim 0:33d4e66780c0 540
IanBenzMaxim 0:33d4e66780c0 541 AssignIfExist(minItems_, value, GetMinItemsString());
IanBenzMaxim 0:33d4e66780c0 542 AssignIfExist(maxItems_, value, GetMaxItemsString());
IanBenzMaxim 0:33d4e66780c0 543
IanBenzMaxim 0:33d4e66780c0 544 if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
IanBenzMaxim 0:33d4e66780c0 545 if (v->IsBool())
IanBenzMaxim 0:33d4e66780c0 546 additionalItems_ = v->GetBool();
IanBenzMaxim 0:33d4e66780c0 547 else if (v->IsObject())
IanBenzMaxim 0:33d4e66780c0 548 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
IanBenzMaxim 0:33d4e66780c0 549 }
IanBenzMaxim 0:33d4e66780c0 550
IanBenzMaxim 0:33d4e66780c0 551 AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
IanBenzMaxim 0:33d4e66780c0 552
IanBenzMaxim 0:33d4e66780c0 553 // String
IanBenzMaxim 0:33d4e66780c0 554 AssignIfExist(minLength_, value, GetMinLengthString());
IanBenzMaxim 0:33d4e66780c0 555 AssignIfExist(maxLength_, value, GetMaxLengthString());
IanBenzMaxim 0:33d4e66780c0 556
IanBenzMaxim 0:33d4e66780c0 557 if (const ValueType* v = GetMember(value, GetPatternString()))
IanBenzMaxim 0:33d4e66780c0 558 pattern_ = CreatePattern(*v);
IanBenzMaxim 0:33d4e66780c0 559
IanBenzMaxim 0:33d4e66780c0 560 // Number
IanBenzMaxim 0:33d4e66780c0 561 if (const ValueType* v = GetMember(value, GetMinimumString()))
IanBenzMaxim 0:33d4e66780c0 562 if (v->IsNumber())
IanBenzMaxim 0:33d4e66780c0 563 minimum_.CopyFrom(*v, *allocator_);
IanBenzMaxim 0:33d4e66780c0 564
IanBenzMaxim 0:33d4e66780c0 565 if (const ValueType* v = GetMember(value, GetMaximumString()))
IanBenzMaxim 0:33d4e66780c0 566 if (v->IsNumber())
IanBenzMaxim 0:33d4e66780c0 567 maximum_.CopyFrom(*v, *allocator_);
IanBenzMaxim 0:33d4e66780c0 568
IanBenzMaxim 0:33d4e66780c0 569 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
IanBenzMaxim 0:33d4e66780c0 570 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
IanBenzMaxim 0:33d4e66780c0 571
IanBenzMaxim 0:33d4e66780c0 572 if (const ValueType* v = GetMember(value, GetMultipleOfString()))
IanBenzMaxim 0:33d4e66780c0 573 if (v->IsNumber() && v->GetDouble() > 0.0)
IanBenzMaxim 0:33d4e66780c0 574 multipleOf_.CopyFrom(*v, *allocator_);
IanBenzMaxim 0:33d4e66780c0 575 }
IanBenzMaxim 0:33d4e66780c0 576
IanBenzMaxim 0:33d4e66780c0 577 ~Schema() {
IanBenzMaxim 0:33d4e66780c0 578 if (allocator_) {
IanBenzMaxim 0:33d4e66780c0 579 allocator_->Free(enum_);
IanBenzMaxim 0:33d4e66780c0 580 }
IanBenzMaxim 0:33d4e66780c0 581 if (properties_) {
IanBenzMaxim 0:33d4e66780c0 582 for (SizeType i = 0; i < propertyCount_; i++)
IanBenzMaxim 0:33d4e66780c0 583 properties_[i].~Property();
IanBenzMaxim 0:33d4e66780c0 584 AllocatorType::Free(properties_);
IanBenzMaxim 0:33d4e66780c0 585 }
IanBenzMaxim 0:33d4e66780c0 586 if (patternProperties_) {
IanBenzMaxim 0:33d4e66780c0 587 for (SizeType i = 0; i < patternPropertyCount_; i++)
IanBenzMaxim 0:33d4e66780c0 588 patternProperties_[i].~PatternProperty();
IanBenzMaxim 0:33d4e66780c0 589 AllocatorType::Free(patternProperties_);
IanBenzMaxim 0:33d4e66780c0 590 }
IanBenzMaxim 0:33d4e66780c0 591 AllocatorType::Free(itemsTuple_);
IanBenzMaxim 0:33d4e66780c0 592 #if RAPIDJSON_SCHEMA_HAS_REGEX
IanBenzMaxim 0:33d4e66780c0 593 if (pattern_) {
IanBenzMaxim 0:33d4e66780c0 594 pattern_->~RegexType();
IanBenzMaxim 0:33d4e66780c0 595 allocator_->Free(pattern_);
IanBenzMaxim 0:33d4e66780c0 596 }
IanBenzMaxim 0:33d4e66780c0 597 #endif
IanBenzMaxim 0:33d4e66780c0 598 }
IanBenzMaxim 0:33d4e66780c0 599
IanBenzMaxim 0:33d4e66780c0 600 bool BeginValue(Context& context) const {
IanBenzMaxim 0:33d4e66780c0 601 if (context.inArray) {
IanBenzMaxim 0:33d4e66780c0 602 if (uniqueItems_)
IanBenzMaxim 0:33d4e66780c0 603 context.valueUniqueness = true;
IanBenzMaxim 0:33d4e66780c0 604
IanBenzMaxim 0:33d4e66780c0 605 if (itemsList_)
IanBenzMaxim 0:33d4e66780c0 606 context.valueSchema = itemsList_;
IanBenzMaxim 0:33d4e66780c0 607 else if (itemsTuple_) {
IanBenzMaxim 0:33d4e66780c0 608 if (context.arrayElementIndex < itemsTupleCount_)
IanBenzMaxim 0:33d4e66780c0 609 context.valueSchema = itemsTuple_[context.arrayElementIndex];
IanBenzMaxim 0:33d4e66780c0 610 else if (additionalItemsSchema_)
IanBenzMaxim 0:33d4e66780c0 611 context.valueSchema = additionalItemsSchema_;
IanBenzMaxim 0:33d4e66780c0 612 else if (additionalItems_)
IanBenzMaxim 0:33d4e66780c0 613 context.valueSchema = GetTypeless();
IanBenzMaxim 0:33d4e66780c0 614 else
IanBenzMaxim 0:33d4e66780c0 615 RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
IanBenzMaxim 0:33d4e66780c0 616 }
IanBenzMaxim 0:33d4e66780c0 617 else
IanBenzMaxim 0:33d4e66780c0 618 context.valueSchema = GetTypeless();
IanBenzMaxim 0:33d4e66780c0 619
IanBenzMaxim 0:33d4e66780c0 620 context.arrayElementIndex++;
IanBenzMaxim 0:33d4e66780c0 621 }
IanBenzMaxim 0:33d4e66780c0 622 return true;
IanBenzMaxim 0:33d4e66780c0 623 }
IanBenzMaxim 0:33d4e66780c0 624
IanBenzMaxim 0:33d4e66780c0 625 RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
IanBenzMaxim 0:33d4e66780c0 626 if (context.patternPropertiesValidatorCount > 0) {
IanBenzMaxim 0:33d4e66780c0 627 bool otherValid = false;
IanBenzMaxim 0:33d4e66780c0 628 SizeType count = context.patternPropertiesValidatorCount;
IanBenzMaxim 0:33d4e66780c0 629 if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
IanBenzMaxim 0:33d4e66780c0 630 otherValid = context.patternPropertiesValidators[--count]->IsValid();
IanBenzMaxim 0:33d4e66780c0 631
IanBenzMaxim 0:33d4e66780c0 632 bool patternValid = true;
IanBenzMaxim 0:33d4e66780c0 633 for (SizeType i = 0; i < count; i++)
IanBenzMaxim 0:33d4e66780c0 634 if (!context.patternPropertiesValidators[i]->IsValid()) {
IanBenzMaxim 0:33d4e66780c0 635 patternValid = false;
IanBenzMaxim 0:33d4e66780c0 636 break;
IanBenzMaxim 0:33d4e66780c0 637 }
IanBenzMaxim 0:33d4e66780c0 638
IanBenzMaxim 0:33d4e66780c0 639 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
IanBenzMaxim 0:33d4e66780c0 640 if (!patternValid)
IanBenzMaxim 0:33d4e66780c0 641 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
IanBenzMaxim 0:33d4e66780c0 642 }
IanBenzMaxim 0:33d4e66780c0 643 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
IanBenzMaxim 0:33d4e66780c0 644 if (!patternValid || !otherValid)
IanBenzMaxim 0:33d4e66780c0 645 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
IanBenzMaxim 0:33d4e66780c0 646 }
IanBenzMaxim 0:33d4e66780c0 647 else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
IanBenzMaxim 0:33d4e66780c0 648 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
IanBenzMaxim 0:33d4e66780c0 649 }
IanBenzMaxim 0:33d4e66780c0 650
IanBenzMaxim 0:33d4e66780c0 651 if (enum_) {
IanBenzMaxim 0:33d4e66780c0 652 const uint64_t h = context.factory.GetHashCode(context.hasher);
IanBenzMaxim 0:33d4e66780c0 653 for (SizeType i = 0; i < enumCount_; i++)
IanBenzMaxim 0:33d4e66780c0 654 if (enum_[i] == h)
IanBenzMaxim 0:33d4e66780c0 655 goto foundEnum;
IanBenzMaxim 0:33d4e66780c0 656 RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
IanBenzMaxim 0:33d4e66780c0 657 foundEnum:;
IanBenzMaxim 0:33d4e66780c0 658 }
IanBenzMaxim 0:33d4e66780c0 659
IanBenzMaxim 0:33d4e66780c0 660 if (allOf_.schemas)
IanBenzMaxim 0:33d4e66780c0 661 for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
IanBenzMaxim 0:33d4e66780c0 662 if (!context.validators[i]->IsValid())
IanBenzMaxim 0:33d4e66780c0 663 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
IanBenzMaxim 0:33d4e66780c0 664
IanBenzMaxim 0:33d4e66780c0 665 if (anyOf_.schemas) {
IanBenzMaxim 0:33d4e66780c0 666 for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
IanBenzMaxim 0:33d4e66780c0 667 if (context.validators[i]->IsValid())
IanBenzMaxim 0:33d4e66780c0 668 goto foundAny;
IanBenzMaxim 0:33d4e66780c0 669 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
IanBenzMaxim 0:33d4e66780c0 670 foundAny:;
IanBenzMaxim 0:33d4e66780c0 671 }
IanBenzMaxim 0:33d4e66780c0 672
IanBenzMaxim 0:33d4e66780c0 673 if (oneOf_.schemas) {
IanBenzMaxim 0:33d4e66780c0 674 bool oneValid = false;
IanBenzMaxim 0:33d4e66780c0 675 for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
IanBenzMaxim 0:33d4e66780c0 676 if (context.validators[i]->IsValid()) {
IanBenzMaxim 0:33d4e66780c0 677 if (oneValid)
IanBenzMaxim 0:33d4e66780c0 678 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
IanBenzMaxim 0:33d4e66780c0 679 else
IanBenzMaxim 0:33d4e66780c0 680 oneValid = true;
IanBenzMaxim 0:33d4e66780c0 681 }
IanBenzMaxim 0:33d4e66780c0 682 if (!oneValid)
IanBenzMaxim 0:33d4e66780c0 683 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
IanBenzMaxim 0:33d4e66780c0 684 }
IanBenzMaxim 0:33d4e66780c0 685
IanBenzMaxim 0:33d4e66780c0 686 if (not_ && context.validators[notValidatorIndex_]->IsValid())
IanBenzMaxim 0:33d4e66780c0 687 RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
IanBenzMaxim 0:33d4e66780c0 688
IanBenzMaxim 0:33d4e66780c0 689 return true;
IanBenzMaxim 0:33d4e66780c0 690 }
IanBenzMaxim 0:33d4e66780c0 691
IanBenzMaxim 0:33d4e66780c0 692 bool Null(Context& context) const {
IanBenzMaxim 0:33d4e66780c0 693 if (!(type_ & (1 << kNullSchemaType)))
IanBenzMaxim 0:33d4e66780c0 694 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
IanBenzMaxim 0:33d4e66780c0 695 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 696 }
IanBenzMaxim 0:33d4e66780c0 697
IanBenzMaxim 0:33d4e66780c0 698 bool Bool(Context& context, bool) const {
IanBenzMaxim 0:33d4e66780c0 699 if (!(type_ & (1 << kBooleanSchemaType)))
IanBenzMaxim 0:33d4e66780c0 700 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
IanBenzMaxim 0:33d4e66780c0 701 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 702 }
IanBenzMaxim 0:33d4e66780c0 703
IanBenzMaxim 0:33d4e66780c0 704 bool Int(Context& context, int i) const {
IanBenzMaxim 0:33d4e66780c0 705 if (!CheckInt(context, i))
IanBenzMaxim 0:33d4e66780c0 706 return false;
IanBenzMaxim 0:33d4e66780c0 707 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 708 }
IanBenzMaxim 0:33d4e66780c0 709
IanBenzMaxim 0:33d4e66780c0 710 bool Uint(Context& context, unsigned u) const {
IanBenzMaxim 0:33d4e66780c0 711 if (!CheckUint(context, u))
IanBenzMaxim 0:33d4e66780c0 712 return false;
IanBenzMaxim 0:33d4e66780c0 713 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 714 }
IanBenzMaxim 0:33d4e66780c0 715
IanBenzMaxim 0:33d4e66780c0 716 bool Int64(Context& context, int64_t i) const {
IanBenzMaxim 0:33d4e66780c0 717 if (!CheckInt(context, i))
IanBenzMaxim 0:33d4e66780c0 718 return false;
IanBenzMaxim 0:33d4e66780c0 719 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 720 }
IanBenzMaxim 0:33d4e66780c0 721
IanBenzMaxim 0:33d4e66780c0 722 bool Uint64(Context& context, uint64_t u) const {
IanBenzMaxim 0:33d4e66780c0 723 if (!CheckUint(context, u))
IanBenzMaxim 0:33d4e66780c0 724 return false;
IanBenzMaxim 0:33d4e66780c0 725 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 726 }
IanBenzMaxim 0:33d4e66780c0 727
IanBenzMaxim 0:33d4e66780c0 728 bool Double(Context& context, double d) const {
IanBenzMaxim 0:33d4e66780c0 729 if (!(type_ & (1 << kNumberSchemaType)))
IanBenzMaxim 0:33d4e66780c0 730 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
IanBenzMaxim 0:33d4e66780c0 731
IanBenzMaxim 0:33d4e66780c0 732 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
IanBenzMaxim 0:33d4e66780c0 733 return false;
IanBenzMaxim 0:33d4e66780c0 734
IanBenzMaxim 0:33d4e66780c0 735 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
IanBenzMaxim 0:33d4e66780c0 736 return false;
IanBenzMaxim 0:33d4e66780c0 737
IanBenzMaxim 0:33d4e66780c0 738 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
IanBenzMaxim 0:33d4e66780c0 739 return false;
IanBenzMaxim 0:33d4e66780c0 740
IanBenzMaxim 0:33d4e66780c0 741 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 742 }
IanBenzMaxim 0:33d4e66780c0 743
IanBenzMaxim 0:33d4e66780c0 744 bool String(Context& context, const Ch* str, SizeType length, bool) const {
IanBenzMaxim 0:33d4e66780c0 745 if (!(type_ & (1 << kStringSchemaType)))
IanBenzMaxim 0:33d4e66780c0 746 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
IanBenzMaxim 0:33d4e66780c0 747
IanBenzMaxim 0:33d4e66780c0 748 if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
IanBenzMaxim 0:33d4e66780c0 749 SizeType count;
IanBenzMaxim 0:33d4e66780c0 750 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
IanBenzMaxim 0:33d4e66780c0 751 if (count < minLength_)
IanBenzMaxim 0:33d4e66780c0 752 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
IanBenzMaxim 0:33d4e66780c0 753 if (count > maxLength_)
IanBenzMaxim 0:33d4e66780c0 754 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
IanBenzMaxim 0:33d4e66780c0 755 }
IanBenzMaxim 0:33d4e66780c0 756 }
IanBenzMaxim 0:33d4e66780c0 757
IanBenzMaxim 0:33d4e66780c0 758 if (pattern_ && !IsPatternMatch(pattern_, str, length))
IanBenzMaxim 0:33d4e66780c0 759 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
IanBenzMaxim 0:33d4e66780c0 760
IanBenzMaxim 0:33d4e66780c0 761 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 762 }
IanBenzMaxim 0:33d4e66780c0 763
IanBenzMaxim 0:33d4e66780c0 764 bool StartObject(Context& context) const {
IanBenzMaxim 0:33d4e66780c0 765 if (!(type_ & (1 << kObjectSchemaType)))
IanBenzMaxim 0:33d4e66780c0 766 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
IanBenzMaxim 0:33d4e66780c0 767
IanBenzMaxim 0:33d4e66780c0 768 if (hasDependencies_ || hasRequired_) {
IanBenzMaxim 0:33d4e66780c0 769 context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
IanBenzMaxim 0:33d4e66780c0 770 std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
IanBenzMaxim 0:33d4e66780c0 771 }
IanBenzMaxim 0:33d4e66780c0 772
IanBenzMaxim 0:33d4e66780c0 773 if (patternProperties_) { // pre-allocate schema array
IanBenzMaxim 0:33d4e66780c0 774 SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
IanBenzMaxim 0:33d4e66780c0 775 context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
IanBenzMaxim 0:33d4e66780c0 776 context.patternPropertiesSchemaCount = 0;
IanBenzMaxim 0:33d4e66780c0 777 std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
IanBenzMaxim 0:33d4e66780c0 778 }
IanBenzMaxim 0:33d4e66780c0 779
IanBenzMaxim 0:33d4e66780c0 780 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 781 }
IanBenzMaxim 0:33d4e66780c0 782
IanBenzMaxim 0:33d4e66780c0 783 bool Key(Context& context, const Ch* str, SizeType len, bool) const {
IanBenzMaxim 0:33d4e66780c0 784 if (patternProperties_) {
IanBenzMaxim 0:33d4e66780c0 785 context.patternPropertiesSchemaCount = 0;
IanBenzMaxim 0:33d4e66780c0 786 for (SizeType i = 0; i < patternPropertyCount_; i++)
IanBenzMaxim 0:33d4e66780c0 787 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
IanBenzMaxim 0:33d4e66780c0 788 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
IanBenzMaxim 0:33d4e66780c0 789 }
IanBenzMaxim 0:33d4e66780c0 790
IanBenzMaxim 0:33d4e66780c0 791 SizeType index;
IanBenzMaxim 0:33d4e66780c0 792 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
IanBenzMaxim 0:33d4e66780c0 793 if (context.patternPropertiesSchemaCount > 0) {
IanBenzMaxim 0:33d4e66780c0 794 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
IanBenzMaxim 0:33d4e66780c0 795 context.valueSchema = GetTypeless();
IanBenzMaxim 0:33d4e66780c0 796 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
IanBenzMaxim 0:33d4e66780c0 797 }
IanBenzMaxim 0:33d4e66780c0 798 else
IanBenzMaxim 0:33d4e66780c0 799 context.valueSchema = properties_[index].schema;
IanBenzMaxim 0:33d4e66780c0 800
IanBenzMaxim 0:33d4e66780c0 801 if (context.propertyExist)
IanBenzMaxim 0:33d4e66780c0 802 context.propertyExist[index] = true;
IanBenzMaxim 0:33d4e66780c0 803
IanBenzMaxim 0:33d4e66780c0 804 return true;
IanBenzMaxim 0:33d4e66780c0 805 }
IanBenzMaxim 0:33d4e66780c0 806
IanBenzMaxim 0:33d4e66780c0 807 if (additionalPropertiesSchema_) {
IanBenzMaxim 0:33d4e66780c0 808 if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
IanBenzMaxim 0:33d4e66780c0 809 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
IanBenzMaxim 0:33d4e66780c0 810 context.valueSchema = GetTypeless();
IanBenzMaxim 0:33d4e66780c0 811 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
IanBenzMaxim 0:33d4e66780c0 812 }
IanBenzMaxim 0:33d4e66780c0 813 else
IanBenzMaxim 0:33d4e66780c0 814 context.valueSchema = additionalPropertiesSchema_;
IanBenzMaxim 0:33d4e66780c0 815 return true;
IanBenzMaxim 0:33d4e66780c0 816 }
IanBenzMaxim 0:33d4e66780c0 817 else if (additionalProperties_) {
IanBenzMaxim 0:33d4e66780c0 818 context.valueSchema = GetTypeless();
IanBenzMaxim 0:33d4e66780c0 819 return true;
IanBenzMaxim 0:33d4e66780c0 820 }
IanBenzMaxim 0:33d4e66780c0 821
IanBenzMaxim 0:33d4e66780c0 822 if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
IanBenzMaxim 0:33d4e66780c0 823 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
IanBenzMaxim 0:33d4e66780c0 824
IanBenzMaxim 0:33d4e66780c0 825 return true;
IanBenzMaxim 0:33d4e66780c0 826 }
IanBenzMaxim 0:33d4e66780c0 827
IanBenzMaxim 0:33d4e66780c0 828 bool EndObject(Context& context, SizeType memberCount) const {
IanBenzMaxim 0:33d4e66780c0 829 if (hasRequired_)
IanBenzMaxim 0:33d4e66780c0 830 for (SizeType index = 0; index < propertyCount_; index++)
IanBenzMaxim 0:33d4e66780c0 831 if (properties_[index].required)
IanBenzMaxim 0:33d4e66780c0 832 if (!context.propertyExist[index])
IanBenzMaxim 0:33d4e66780c0 833 RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
IanBenzMaxim 0:33d4e66780c0 834
IanBenzMaxim 0:33d4e66780c0 835 if (memberCount < minProperties_)
IanBenzMaxim 0:33d4e66780c0 836 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
IanBenzMaxim 0:33d4e66780c0 837
IanBenzMaxim 0:33d4e66780c0 838 if (memberCount > maxProperties_)
IanBenzMaxim 0:33d4e66780c0 839 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
IanBenzMaxim 0:33d4e66780c0 840
IanBenzMaxim 0:33d4e66780c0 841 if (hasDependencies_) {
IanBenzMaxim 0:33d4e66780c0 842 for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
IanBenzMaxim 0:33d4e66780c0 843 if (context.propertyExist[sourceIndex]) {
IanBenzMaxim 0:33d4e66780c0 844 if (properties_[sourceIndex].dependencies) {
IanBenzMaxim 0:33d4e66780c0 845 for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
IanBenzMaxim 0:33d4e66780c0 846 if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
IanBenzMaxim 0:33d4e66780c0 847 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
IanBenzMaxim 0:33d4e66780c0 848 }
IanBenzMaxim 0:33d4e66780c0 849 else if (properties_[sourceIndex].dependenciesSchema)
IanBenzMaxim 0:33d4e66780c0 850 if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
IanBenzMaxim 0:33d4e66780c0 851 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
IanBenzMaxim 0:33d4e66780c0 852 }
IanBenzMaxim 0:33d4e66780c0 853 }
IanBenzMaxim 0:33d4e66780c0 854
IanBenzMaxim 0:33d4e66780c0 855 return true;
IanBenzMaxim 0:33d4e66780c0 856 }
IanBenzMaxim 0:33d4e66780c0 857
IanBenzMaxim 0:33d4e66780c0 858 bool StartArray(Context& context) const {
IanBenzMaxim 0:33d4e66780c0 859 if (!(type_ & (1 << kArraySchemaType)))
IanBenzMaxim 0:33d4e66780c0 860 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
IanBenzMaxim 0:33d4e66780c0 861
IanBenzMaxim 0:33d4e66780c0 862 context.arrayElementIndex = 0;
IanBenzMaxim 0:33d4e66780c0 863 context.inArray = true;
IanBenzMaxim 0:33d4e66780c0 864
IanBenzMaxim 0:33d4e66780c0 865 return CreateParallelValidator(context);
IanBenzMaxim 0:33d4e66780c0 866 }
IanBenzMaxim 0:33d4e66780c0 867
IanBenzMaxim 0:33d4e66780c0 868 bool EndArray(Context& context, SizeType elementCount) const {
IanBenzMaxim 0:33d4e66780c0 869 context.inArray = false;
IanBenzMaxim 0:33d4e66780c0 870
IanBenzMaxim 0:33d4e66780c0 871 if (elementCount < minItems_)
IanBenzMaxim 0:33d4e66780c0 872 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
IanBenzMaxim 0:33d4e66780c0 873
IanBenzMaxim 0:33d4e66780c0 874 if (elementCount > maxItems_)
IanBenzMaxim 0:33d4e66780c0 875 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
IanBenzMaxim 0:33d4e66780c0 876
IanBenzMaxim 0:33d4e66780c0 877 return true;
IanBenzMaxim 0:33d4e66780c0 878 }
IanBenzMaxim 0:33d4e66780c0 879
IanBenzMaxim 0:33d4e66780c0 880 // Generate functions for string literal according to Ch
IanBenzMaxim 0:33d4e66780c0 881 #define RAPIDJSON_STRING_(name, ...) \
IanBenzMaxim 0:33d4e66780c0 882 static const ValueType& Get##name##String() {\
IanBenzMaxim 0:33d4e66780c0 883 static const Ch s[] = { __VA_ARGS__, '\0' };\
IanBenzMaxim 0:33d4e66780c0 884 static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\
IanBenzMaxim 0:33d4e66780c0 885 return v;\
IanBenzMaxim 0:33d4e66780c0 886 }
IanBenzMaxim 0:33d4e66780c0 887
IanBenzMaxim 0:33d4e66780c0 888 RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
IanBenzMaxim 0:33d4e66780c0 889 RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
IanBenzMaxim 0:33d4e66780c0 890 RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
IanBenzMaxim 0:33d4e66780c0 891 RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
IanBenzMaxim 0:33d4e66780c0 892 RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
IanBenzMaxim 0:33d4e66780c0 893 RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
IanBenzMaxim 0:33d4e66780c0 894 RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
IanBenzMaxim 0:33d4e66780c0 895 RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
IanBenzMaxim 0:33d4e66780c0 896 RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
IanBenzMaxim 0:33d4e66780c0 897 RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
IanBenzMaxim 0:33d4e66780c0 898 RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
IanBenzMaxim 0:33d4e66780c0 899 RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
IanBenzMaxim 0:33d4e66780c0 900 RAPIDJSON_STRING_(Not, 'n', 'o', 't')
IanBenzMaxim 0:33d4e66780c0 901 RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
IanBenzMaxim 0:33d4e66780c0 902 RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
IanBenzMaxim 0:33d4e66780c0 903 RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
IanBenzMaxim 0:33d4e66780c0 904 RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
IanBenzMaxim 0:33d4e66780c0 905 RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
IanBenzMaxim 0:33d4e66780c0 906 RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
IanBenzMaxim 0:33d4e66780c0 907 RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
IanBenzMaxim 0:33d4e66780c0 908 RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
IanBenzMaxim 0:33d4e66780c0 909 RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
IanBenzMaxim 0:33d4e66780c0 910 RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
IanBenzMaxim 0:33d4e66780c0 911 RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
IanBenzMaxim 0:33d4e66780c0 912 RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
IanBenzMaxim 0:33d4e66780c0 913 RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
IanBenzMaxim 0:33d4e66780c0 914 RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
IanBenzMaxim 0:33d4e66780c0 915 RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
IanBenzMaxim 0:33d4e66780c0 916 RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
IanBenzMaxim 0:33d4e66780c0 917 RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
IanBenzMaxim 0:33d4e66780c0 918 RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
IanBenzMaxim 0:33d4e66780c0 919 RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
IanBenzMaxim 0:33d4e66780c0 920 RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
IanBenzMaxim 0:33d4e66780c0 921
IanBenzMaxim 0:33d4e66780c0 922 #undef RAPIDJSON_STRING_
IanBenzMaxim 0:33d4e66780c0 923
IanBenzMaxim 0:33d4e66780c0 924 private:
IanBenzMaxim 0:33d4e66780c0 925 enum SchemaValueType {
IanBenzMaxim 0:33d4e66780c0 926 kNullSchemaType,
IanBenzMaxim 0:33d4e66780c0 927 kBooleanSchemaType,
IanBenzMaxim 0:33d4e66780c0 928 kObjectSchemaType,
IanBenzMaxim 0:33d4e66780c0 929 kArraySchemaType,
IanBenzMaxim 0:33d4e66780c0 930 kStringSchemaType,
IanBenzMaxim 0:33d4e66780c0 931 kNumberSchemaType,
IanBenzMaxim 0:33d4e66780c0 932 kIntegerSchemaType,
IanBenzMaxim 0:33d4e66780c0 933 kTotalSchemaType
IanBenzMaxim 0:33d4e66780c0 934 };
IanBenzMaxim 0:33d4e66780c0 935
IanBenzMaxim 0:33d4e66780c0 936 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
IanBenzMaxim 0:33d4e66780c0 937 typedef internal::GenericRegex<EncodingType> RegexType;
IanBenzMaxim 0:33d4e66780c0 938 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
IanBenzMaxim 0:33d4e66780c0 939 typedef std::basic_regex<Ch> RegexType;
IanBenzMaxim 0:33d4e66780c0 940 #else
IanBenzMaxim 0:33d4e66780c0 941 typedef char RegexType;
IanBenzMaxim 0:33d4e66780c0 942 #endif
IanBenzMaxim 0:33d4e66780c0 943
IanBenzMaxim 0:33d4e66780c0 944 struct SchemaArray {
IanBenzMaxim 0:33d4e66780c0 945 SchemaArray() : schemas(), count() {}
IanBenzMaxim 0:33d4e66780c0 946 ~SchemaArray() { AllocatorType::Free(schemas); }
IanBenzMaxim 0:33d4e66780c0 947 const SchemaType** schemas;
IanBenzMaxim 0:33d4e66780c0 948 SizeType begin; // begin index of context.validators
IanBenzMaxim 0:33d4e66780c0 949 SizeType count;
IanBenzMaxim 0:33d4e66780c0 950 };
IanBenzMaxim 0:33d4e66780c0 951
IanBenzMaxim 0:33d4e66780c0 952 static const SchemaType* GetTypeless() {
IanBenzMaxim 0:33d4e66780c0 953 static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
IanBenzMaxim 0:33d4e66780c0 954 return &typeless;
IanBenzMaxim 0:33d4e66780c0 955 }
IanBenzMaxim 0:33d4e66780c0 956
IanBenzMaxim 0:33d4e66780c0 957 template <typename V1, typename V2>
IanBenzMaxim 0:33d4e66780c0 958 void AddUniqueElement(V1& a, const V2& v) {
IanBenzMaxim 0:33d4e66780c0 959 for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
IanBenzMaxim 0:33d4e66780c0 960 if (*itr == v)
IanBenzMaxim 0:33d4e66780c0 961 return;
IanBenzMaxim 0:33d4e66780c0 962 V1 c(v, *allocator_);
IanBenzMaxim 0:33d4e66780c0 963 a.PushBack(c, *allocator_);
IanBenzMaxim 0:33d4e66780c0 964 }
IanBenzMaxim 0:33d4e66780c0 965
IanBenzMaxim 0:33d4e66780c0 966 static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
IanBenzMaxim 0:33d4e66780c0 967 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
IanBenzMaxim 0:33d4e66780c0 968 return itr != value.MemberEnd() ? &(itr->value) : 0;
IanBenzMaxim 0:33d4e66780c0 969 }
IanBenzMaxim 0:33d4e66780c0 970
IanBenzMaxim 0:33d4e66780c0 971 static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
IanBenzMaxim 0:33d4e66780c0 972 if (const ValueType* v = GetMember(value, name))
IanBenzMaxim 0:33d4e66780c0 973 if (v->IsBool())
IanBenzMaxim 0:33d4e66780c0 974 out = v->GetBool();
IanBenzMaxim 0:33d4e66780c0 975 }
IanBenzMaxim 0:33d4e66780c0 976
IanBenzMaxim 0:33d4e66780c0 977 static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
IanBenzMaxim 0:33d4e66780c0 978 if (const ValueType* v = GetMember(value, name))
IanBenzMaxim 0:33d4e66780c0 979 if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
IanBenzMaxim 0:33d4e66780c0 980 out = static_cast<SizeType>(v->GetUint64());
IanBenzMaxim 0:33d4e66780c0 981 }
IanBenzMaxim 0:33d4e66780c0 982
IanBenzMaxim 0:33d4e66780c0 983 void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
IanBenzMaxim 0:33d4e66780c0 984 if (const ValueType* v = GetMember(value, name)) {
IanBenzMaxim 0:33d4e66780c0 985 if (v->IsArray() && v->Size() > 0) {
IanBenzMaxim 0:33d4e66780c0 986 PointerType q = p.Append(name, allocator_);
IanBenzMaxim 0:33d4e66780c0 987 out.count = v->Size();
IanBenzMaxim 0:33d4e66780c0 988 out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
IanBenzMaxim 0:33d4e66780c0 989 memset(out.schemas, 0, sizeof(Schema*)* out.count);
IanBenzMaxim 0:33d4e66780c0 990 for (SizeType i = 0; i < out.count; i++)
IanBenzMaxim 0:33d4e66780c0 991 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
IanBenzMaxim 0:33d4e66780c0 992 out.begin = validatorCount_;
IanBenzMaxim 0:33d4e66780c0 993 validatorCount_ += out.count;
IanBenzMaxim 0:33d4e66780c0 994 }
IanBenzMaxim 0:33d4e66780c0 995 }
IanBenzMaxim 0:33d4e66780c0 996 }
IanBenzMaxim 0:33d4e66780c0 997
IanBenzMaxim 0:33d4e66780c0 998 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
IanBenzMaxim 0:33d4e66780c0 999 template <typename ValueType>
IanBenzMaxim 0:33d4e66780c0 1000 RegexType* CreatePattern(const ValueType& value) {
IanBenzMaxim 0:33d4e66780c0 1001 if (value.IsString()) {
IanBenzMaxim 0:33d4e66780c0 1002 RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
IanBenzMaxim 0:33d4e66780c0 1003 if (!r->IsValid()) {
IanBenzMaxim 0:33d4e66780c0 1004 r->~RegexType();
IanBenzMaxim 0:33d4e66780c0 1005 AllocatorType::Free(r);
IanBenzMaxim 0:33d4e66780c0 1006 r = 0;
IanBenzMaxim 0:33d4e66780c0 1007 }
IanBenzMaxim 0:33d4e66780c0 1008 return r;
IanBenzMaxim 0:33d4e66780c0 1009 }
IanBenzMaxim 0:33d4e66780c0 1010 return 0;
IanBenzMaxim 0:33d4e66780c0 1011 }
IanBenzMaxim 0:33d4e66780c0 1012
IanBenzMaxim 0:33d4e66780c0 1013 static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
IanBenzMaxim 0:33d4e66780c0 1014 GenericRegexSearch<RegexType> rs(*pattern);
IanBenzMaxim 0:33d4e66780c0 1015 return rs.Search(str);
IanBenzMaxim 0:33d4e66780c0 1016 }
IanBenzMaxim 0:33d4e66780c0 1017 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
IanBenzMaxim 0:33d4e66780c0 1018 template <typename ValueType>
IanBenzMaxim 0:33d4e66780c0 1019 RegexType* CreatePattern(const ValueType& value) {
IanBenzMaxim 0:33d4e66780c0 1020 if (value.IsString())
IanBenzMaxim 0:33d4e66780c0 1021 try {
IanBenzMaxim 0:33d4e66780c0 1022 return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
IanBenzMaxim 0:33d4e66780c0 1023 }
IanBenzMaxim 0:33d4e66780c0 1024 catch (const std::regex_error&) {
IanBenzMaxim 0:33d4e66780c0 1025 }
IanBenzMaxim 0:33d4e66780c0 1026 return 0;
IanBenzMaxim 0:33d4e66780c0 1027 }
IanBenzMaxim 0:33d4e66780c0 1028
IanBenzMaxim 0:33d4e66780c0 1029 static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
IanBenzMaxim 0:33d4e66780c0 1030 std::match_results<const Ch*> r;
IanBenzMaxim 0:33d4e66780c0 1031 return std::regex_search(str, str + length, r, *pattern);
IanBenzMaxim 0:33d4e66780c0 1032 }
IanBenzMaxim 0:33d4e66780c0 1033 #else
IanBenzMaxim 0:33d4e66780c0 1034 template <typename ValueType>
IanBenzMaxim 0:33d4e66780c0 1035 RegexType* CreatePattern(const ValueType&) { return 0; }
IanBenzMaxim 0:33d4e66780c0 1036
IanBenzMaxim 0:33d4e66780c0 1037 static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
IanBenzMaxim 0:33d4e66780c0 1038 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
IanBenzMaxim 0:33d4e66780c0 1039
IanBenzMaxim 0:33d4e66780c0 1040 void AddType(const ValueType& type) {
IanBenzMaxim 0:33d4e66780c0 1041 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
IanBenzMaxim 0:33d4e66780c0 1042 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
IanBenzMaxim 0:33d4e66780c0 1043 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
IanBenzMaxim 0:33d4e66780c0 1044 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
IanBenzMaxim 0:33d4e66780c0 1045 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
IanBenzMaxim 0:33d4e66780c0 1046 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
IanBenzMaxim 0:33d4e66780c0 1047 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
IanBenzMaxim 0:33d4e66780c0 1048 }
IanBenzMaxim 0:33d4e66780c0 1049
IanBenzMaxim 0:33d4e66780c0 1050 bool CreateParallelValidator(Context& context) const {
IanBenzMaxim 0:33d4e66780c0 1051 if (enum_ || context.arrayUniqueness)
IanBenzMaxim 0:33d4e66780c0 1052 context.hasher = context.factory.CreateHasher();
IanBenzMaxim 0:33d4e66780c0 1053
IanBenzMaxim 0:33d4e66780c0 1054 if (validatorCount_) {
IanBenzMaxim 0:33d4e66780c0 1055 RAPIDJSON_ASSERT(context.validators == 0);
IanBenzMaxim 0:33d4e66780c0 1056 context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
IanBenzMaxim 0:33d4e66780c0 1057 context.validatorCount = validatorCount_;
IanBenzMaxim 0:33d4e66780c0 1058
IanBenzMaxim 0:33d4e66780c0 1059 if (allOf_.schemas)
IanBenzMaxim 0:33d4e66780c0 1060 CreateSchemaValidators(context, allOf_);
IanBenzMaxim 0:33d4e66780c0 1061
IanBenzMaxim 0:33d4e66780c0 1062 if (anyOf_.schemas)
IanBenzMaxim 0:33d4e66780c0 1063 CreateSchemaValidators(context, anyOf_);
IanBenzMaxim 0:33d4e66780c0 1064
IanBenzMaxim 0:33d4e66780c0 1065 if (oneOf_.schemas)
IanBenzMaxim 0:33d4e66780c0 1066 CreateSchemaValidators(context, oneOf_);
IanBenzMaxim 0:33d4e66780c0 1067
IanBenzMaxim 0:33d4e66780c0 1068 if (not_)
IanBenzMaxim 0:33d4e66780c0 1069 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
IanBenzMaxim 0:33d4e66780c0 1070
IanBenzMaxim 0:33d4e66780c0 1071 if (hasSchemaDependencies_) {
IanBenzMaxim 0:33d4e66780c0 1072 for (SizeType i = 0; i < propertyCount_; i++)
IanBenzMaxim 0:33d4e66780c0 1073 if (properties_[i].dependenciesSchema)
IanBenzMaxim 0:33d4e66780c0 1074 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
IanBenzMaxim 0:33d4e66780c0 1075 }
IanBenzMaxim 0:33d4e66780c0 1076 }
IanBenzMaxim 0:33d4e66780c0 1077
IanBenzMaxim 0:33d4e66780c0 1078 return true;
IanBenzMaxim 0:33d4e66780c0 1079 }
IanBenzMaxim 0:33d4e66780c0 1080
IanBenzMaxim 0:33d4e66780c0 1081 void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
IanBenzMaxim 0:33d4e66780c0 1082 for (SizeType i = 0; i < schemas.count; i++)
IanBenzMaxim 0:33d4e66780c0 1083 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
IanBenzMaxim 0:33d4e66780c0 1084 }
IanBenzMaxim 0:33d4e66780c0 1085
IanBenzMaxim 0:33d4e66780c0 1086 // O(n)
IanBenzMaxim 0:33d4e66780c0 1087 bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
IanBenzMaxim 0:33d4e66780c0 1088 SizeType len = name.GetStringLength();
IanBenzMaxim 0:33d4e66780c0 1089 const Ch* str = name.GetString();
IanBenzMaxim 0:33d4e66780c0 1090 for (SizeType index = 0; index < propertyCount_; index++)
IanBenzMaxim 0:33d4e66780c0 1091 if (properties_[index].name.GetStringLength() == len &&
IanBenzMaxim 0:33d4e66780c0 1092 (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
IanBenzMaxim 0:33d4e66780c0 1093 {
IanBenzMaxim 0:33d4e66780c0 1094 *outIndex = index;
IanBenzMaxim 0:33d4e66780c0 1095 return true;
IanBenzMaxim 0:33d4e66780c0 1096 }
IanBenzMaxim 0:33d4e66780c0 1097 return false;
IanBenzMaxim 0:33d4e66780c0 1098 }
IanBenzMaxim 0:33d4e66780c0 1099
IanBenzMaxim 0:33d4e66780c0 1100 bool CheckInt(Context& context, int64_t i) const {
IanBenzMaxim 0:33d4e66780c0 1101 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
IanBenzMaxim 0:33d4e66780c0 1102 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
IanBenzMaxim 0:33d4e66780c0 1103
IanBenzMaxim 0:33d4e66780c0 1104 if (!minimum_.IsNull()) {
IanBenzMaxim 0:33d4e66780c0 1105 if (minimum_.IsInt64()) {
IanBenzMaxim 0:33d4e66780c0 1106 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
IanBenzMaxim 0:33d4e66780c0 1107 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
IanBenzMaxim 0:33d4e66780c0 1108 }
IanBenzMaxim 0:33d4e66780c0 1109 else if (minimum_.IsUint64()) {
IanBenzMaxim 0:33d4e66780c0 1110 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
IanBenzMaxim 0:33d4e66780c0 1111 }
IanBenzMaxim 0:33d4e66780c0 1112 else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
IanBenzMaxim 0:33d4e66780c0 1113 return false;
IanBenzMaxim 0:33d4e66780c0 1114 }
IanBenzMaxim 0:33d4e66780c0 1115
IanBenzMaxim 0:33d4e66780c0 1116 if (!maximum_.IsNull()) {
IanBenzMaxim 0:33d4e66780c0 1117 if (maximum_.IsInt64()) {
IanBenzMaxim 0:33d4e66780c0 1118 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
IanBenzMaxim 0:33d4e66780c0 1119 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
IanBenzMaxim 0:33d4e66780c0 1120 }
IanBenzMaxim 0:33d4e66780c0 1121 else if (maximum_.IsUint64())
IanBenzMaxim 0:33d4e66780c0 1122 /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
IanBenzMaxim 0:33d4e66780c0 1123 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
IanBenzMaxim 0:33d4e66780c0 1124 return false;
IanBenzMaxim 0:33d4e66780c0 1125 }
IanBenzMaxim 0:33d4e66780c0 1126
IanBenzMaxim 0:33d4e66780c0 1127 if (!multipleOf_.IsNull()) {
IanBenzMaxim 0:33d4e66780c0 1128 if (multipleOf_.IsUint64()) {
IanBenzMaxim 0:33d4e66780c0 1129 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
IanBenzMaxim 0:33d4e66780c0 1130 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
IanBenzMaxim 0:33d4e66780c0 1131 }
IanBenzMaxim 0:33d4e66780c0 1132 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
IanBenzMaxim 0:33d4e66780c0 1133 return false;
IanBenzMaxim 0:33d4e66780c0 1134 }
IanBenzMaxim 0:33d4e66780c0 1135
IanBenzMaxim 0:33d4e66780c0 1136 return true;
IanBenzMaxim 0:33d4e66780c0 1137 }
IanBenzMaxim 0:33d4e66780c0 1138
IanBenzMaxim 0:33d4e66780c0 1139 bool CheckUint(Context& context, uint64_t i) const {
IanBenzMaxim 0:33d4e66780c0 1140 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
IanBenzMaxim 0:33d4e66780c0 1141 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
IanBenzMaxim 0:33d4e66780c0 1142
IanBenzMaxim 0:33d4e66780c0 1143 if (!minimum_.IsNull()) {
IanBenzMaxim 0:33d4e66780c0 1144 if (minimum_.IsUint64()) {
IanBenzMaxim 0:33d4e66780c0 1145 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
IanBenzMaxim 0:33d4e66780c0 1146 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
IanBenzMaxim 0:33d4e66780c0 1147 }
IanBenzMaxim 0:33d4e66780c0 1148 else if (minimum_.IsInt64())
IanBenzMaxim 0:33d4e66780c0 1149 /* do nothing */; // i >= 0 > minimum.Getint64()
IanBenzMaxim 0:33d4e66780c0 1150 else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
IanBenzMaxim 0:33d4e66780c0 1151 return false;
IanBenzMaxim 0:33d4e66780c0 1152 }
IanBenzMaxim 0:33d4e66780c0 1153
IanBenzMaxim 0:33d4e66780c0 1154 if (!maximum_.IsNull()) {
IanBenzMaxim 0:33d4e66780c0 1155 if (maximum_.IsUint64()) {
IanBenzMaxim 0:33d4e66780c0 1156 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
IanBenzMaxim 0:33d4e66780c0 1157 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
IanBenzMaxim 0:33d4e66780c0 1158 }
IanBenzMaxim 0:33d4e66780c0 1159 else if (maximum_.IsInt64())
IanBenzMaxim 0:33d4e66780c0 1160 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
IanBenzMaxim 0:33d4e66780c0 1161 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
IanBenzMaxim 0:33d4e66780c0 1162 return false;
IanBenzMaxim 0:33d4e66780c0 1163 }
IanBenzMaxim 0:33d4e66780c0 1164
IanBenzMaxim 0:33d4e66780c0 1165 if (!multipleOf_.IsNull()) {
IanBenzMaxim 0:33d4e66780c0 1166 if (multipleOf_.IsUint64()) {
IanBenzMaxim 0:33d4e66780c0 1167 if (i % multipleOf_.GetUint64() != 0)
IanBenzMaxim 0:33d4e66780c0 1168 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
IanBenzMaxim 0:33d4e66780c0 1169 }
IanBenzMaxim 0:33d4e66780c0 1170 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
IanBenzMaxim 0:33d4e66780c0 1171 return false;
IanBenzMaxim 0:33d4e66780c0 1172 }
IanBenzMaxim 0:33d4e66780c0 1173
IanBenzMaxim 0:33d4e66780c0 1174 return true;
IanBenzMaxim 0:33d4e66780c0 1175 }
IanBenzMaxim 0:33d4e66780c0 1176
IanBenzMaxim 0:33d4e66780c0 1177 bool CheckDoubleMinimum(Context& context, double d) const {
IanBenzMaxim 0:33d4e66780c0 1178 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
IanBenzMaxim 0:33d4e66780c0 1179 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
IanBenzMaxim 0:33d4e66780c0 1180 return true;
IanBenzMaxim 0:33d4e66780c0 1181 }
IanBenzMaxim 0:33d4e66780c0 1182
IanBenzMaxim 0:33d4e66780c0 1183 bool CheckDoubleMaximum(Context& context, double d) const {
IanBenzMaxim 0:33d4e66780c0 1184 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
IanBenzMaxim 0:33d4e66780c0 1185 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
IanBenzMaxim 0:33d4e66780c0 1186 return true;
IanBenzMaxim 0:33d4e66780c0 1187 }
IanBenzMaxim 0:33d4e66780c0 1188
IanBenzMaxim 0:33d4e66780c0 1189 bool CheckDoubleMultipleOf(Context& context, double d) const {
IanBenzMaxim 0:33d4e66780c0 1190 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
IanBenzMaxim 0:33d4e66780c0 1191 double q = std::floor(a / b);
IanBenzMaxim 0:33d4e66780c0 1192 double r = a - q * b;
IanBenzMaxim 0:33d4e66780c0 1193 if (r > 0.0)
IanBenzMaxim 0:33d4e66780c0 1194 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
IanBenzMaxim 0:33d4e66780c0 1195 return true;
IanBenzMaxim 0:33d4e66780c0 1196 }
IanBenzMaxim 0:33d4e66780c0 1197
IanBenzMaxim 0:33d4e66780c0 1198 struct Property {
IanBenzMaxim 0:33d4e66780c0 1199 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
IanBenzMaxim 0:33d4e66780c0 1200 ~Property() { AllocatorType::Free(dependencies); }
IanBenzMaxim 0:33d4e66780c0 1201 SValue name;
IanBenzMaxim 0:33d4e66780c0 1202 const SchemaType* schema;
IanBenzMaxim 0:33d4e66780c0 1203 const SchemaType* dependenciesSchema;
IanBenzMaxim 0:33d4e66780c0 1204 SizeType dependenciesValidatorIndex;
IanBenzMaxim 0:33d4e66780c0 1205 bool* dependencies;
IanBenzMaxim 0:33d4e66780c0 1206 bool required;
IanBenzMaxim 0:33d4e66780c0 1207 };
IanBenzMaxim 0:33d4e66780c0 1208
IanBenzMaxim 0:33d4e66780c0 1209 struct PatternProperty {
IanBenzMaxim 0:33d4e66780c0 1210 PatternProperty() : schema(), pattern() {}
IanBenzMaxim 0:33d4e66780c0 1211 ~PatternProperty() {
IanBenzMaxim 0:33d4e66780c0 1212 if (pattern) {
IanBenzMaxim 0:33d4e66780c0 1213 pattern->~RegexType();
IanBenzMaxim 0:33d4e66780c0 1214 AllocatorType::Free(pattern);
IanBenzMaxim 0:33d4e66780c0 1215 }
IanBenzMaxim 0:33d4e66780c0 1216 }
IanBenzMaxim 0:33d4e66780c0 1217 const SchemaType* schema;
IanBenzMaxim 0:33d4e66780c0 1218 RegexType* pattern;
IanBenzMaxim 0:33d4e66780c0 1219 };
IanBenzMaxim 0:33d4e66780c0 1220
IanBenzMaxim 0:33d4e66780c0 1221 AllocatorType* allocator_;
IanBenzMaxim 0:33d4e66780c0 1222 uint64_t* enum_;
IanBenzMaxim 0:33d4e66780c0 1223 SizeType enumCount_;
IanBenzMaxim 0:33d4e66780c0 1224 SchemaArray allOf_;
IanBenzMaxim 0:33d4e66780c0 1225 SchemaArray anyOf_;
IanBenzMaxim 0:33d4e66780c0 1226 SchemaArray oneOf_;
IanBenzMaxim 0:33d4e66780c0 1227 const SchemaType* not_;
IanBenzMaxim 0:33d4e66780c0 1228 unsigned type_; // bitmask of kSchemaType
IanBenzMaxim 0:33d4e66780c0 1229 SizeType validatorCount_;
IanBenzMaxim 0:33d4e66780c0 1230 SizeType notValidatorIndex_;
IanBenzMaxim 0:33d4e66780c0 1231
IanBenzMaxim 0:33d4e66780c0 1232 Property* properties_;
IanBenzMaxim 0:33d4e66780c0 1233 const SchemaType* additionalPropertiesSchema_;
IanBenzMaxim 0:33d4e66780c0 1234 PatternProperty* patternProperties_;
IanBenzMaxim 0:33d4e66780c0 1235 SizeType patternPropertyCount_;
IanBenzMaxim 0:33d4e66780c0 1236 SizeType propertyCount_;
IanBenzMaxim 0:33d4e66780c0 1237 SizeType minProperties_;
IanBenzMaxim 0:33d4e66780c0 1238 SizeType maxProperties_;
IanBenzMaxim 0:33d4e66780c0 1239 bool additionalProperties_;
IanBenzMaxim 0:33d4e66780c0 1240 bool hasDependencies_;
IanBenzMaxim 0:33d4e66780c0 1241 bool hasRequired_;
IanBenzMaxim 0:33d4e66780c0 1242 bool hasSchemaDependencies_;
IanBenzMaxim 0:33d4e66780c0 1243
IanBenzMaxim 0:33d4e66780c0 1244 const SchemaType* additionalItemsSchema_;
IanBenzMaxim 0:33d4e66780c0 1245 const SchemaType* itemsList_;
IanBenzMaxim 0:33d4e66780c0 1246 const SchemaType** itemsTuple_;
IanBenzMaxim 0:33d4e66780c0 1247 SizeType itemsTupleCount_;
IanBenzMaxim 0:33d4e66780c0 1248 SizeType minItems_;
IanBenzMaxim 0:33d4e66780c0 1249 SizeType maxItems_;
IanBenzMaxim 0:33d4e66780c0 1250 bool additionalItems_;
IanBenzMaxim 0:33d4e66780c0 1251 bool uniqueItems_;
IanBenzMaxim 0:33d4e66780c0 1252
IanBenzMaxim 0:33d4e66780c0 1253 RegexType* pattern_;
IanBenzMaxim 0:33d4e66780c0 1254 SizeType minLength_;
IanBenzMaxim 0:33d4e66780c0 1255 SizeType maxLength_;
IanBenzMaxim 0:33d4e66780c0 1256
IanBenzMaxim 0:33d4e66780c0 1257 SValue minimum_;
IanBenzMaxim 0:33d4e66780c0 1258 SValue maximum_;
IanBenzMaxim 0:33d4e66780c0 1259 SValue multipleOf_;
IanBenzMaxim 0:33d4e66780c0 1260 bool exclusiveMinimum_;
IanBenzMaxim 0:33d4e66780c0 1261 bool exclusiveMaximum_;
IanBenzMaxim 0:33d4e66780c0 1262 };
IanBenzMaxim 0:33d4e66780c0 1263
IanBenzMaxim 0:33d4e66780c0 1264 template<typename Stack, typename Ch>
IanBenzMaxim 0:33d4e66780c0 1265 struct TokenHelper {
IanBenzMaxim 0:33d4e66780c0 1266 RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
IanBenzMaxim 0:33d4e66780c0 1267 *documentStack.template Push<Ch>() = '/';
IanBenzMaxim 0:33d4e66780c0 1268 char buffer[21];
IanBenzMaxim 0:33d4e66780c0 1269 size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
IanBenzMaxim 0:33d4e66780c0 1270 for (size_t i = 0; i < length; i++)
IanBenzMaxim 0:33d4e66780c0 1271 *documentStack.template Push<Ch>() = buffer[i];
IanBenzMaxim 0:33d4e66780c0 1272 }
IanBenzMaxim 0:33d4e66780c0 1273 };
IanBenzMaxim 0:33d4e66780c0 1274
IanBenzMaxim 0:33d4e66780c0 1275 // Partial specialized version for char to prevent buffer copying.
IanBenzMaxim 0:33d4e66780c0 1276 template <typename Stack>
IanBenzMaxim 0:33d4e66780c0 1277 struct TokenHelper<Stack, char> {
IanBenzMaxim 0:33d4e66780c0 1278 RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
IanBenzMaxim 0:33d4e66780c0 1279 if (sizeof(SizeType) == 4) {
IanBenzMaxim 0:33d4e66780c0 1280 char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
IanBenzMaxim 0:33d4e66780c0 1281 *buffer++ = '/';
IanBenzMaxim 0:33d4e66780c0 1282 const char* end = internal::u32toa(index, buffer);
IanBenzMaxim 0:33d4e66780c0 1283 documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
IanBenzMaxim 0:33d4e66780c0 1284 }
IanBenzMaxim 0:33d4e66780c0 1285 else {
IanBenzMaxim 0:33d4e66780c0 1286 char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
IanBenzMaxim 0:33d4e66780c0 1287 *buffer++ = '/';
IanBenzMaxim 0:33d4e66780c0 1288 const char* end = internal::u64toa(index, buffer);
IanBenzMaxim 0:33d4e66780c0 1289 documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
IanBenzMaxim 0:33d4e66780c0 1290 }
IanBenzMaxim 0:33d4e66780c0 1291 }
IanBenzMaxim 0:33d4e66780c0 1292 };
IanBenzMaxim 0:33d4e66780c0 1293
IanBenzMaxim 0:33d4e66780c0 1294 } // namespace internal
IanBenzMaxim 0:33d4e66780c0 1295
IanBenzMaxim 0:33d4e66780c0 1296 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 1297 // IGenericRemoteSchemaDocumentProvider
IanBenzMaxim 0:33d4e66780c0 1298
IanBenzMaxim 0:33d4e66780c0 1299 template <typename SchemaDocumentType>
IanBenzMaxim 0:33d4e66780c0 1300 class IGenericRemoteSchemaDocumentProvider {
IanBenzMaxim 0:33d4e66780c0 1301 public:
IanBenzMaxim 0:33d4e66780c0 1302 typedef typename SchemaDocumentType::Ch Ch;
IanBenzMaxim 0:33d4e66780c0 1303
IanBenzMaxim 0:33d4e66780c0 1304 virtual ~IGenericRemoteSchemaDocumentProvider() {}
IanBenzMaxim 0:33d4e66780c0 1305 virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
IanBenzMaxim 0:33d4e66780c0 1306 };
IanBenzMaxim 0:33d4e66780c0 1307
IanBenzMaxim 0:33d4e66780c0 1308 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 1309 // GenericSchemaDocument
IanBenzMaxim 0:33d4e66780c0 1310
IanBenzMaxim 0:33d4e66780c0 1311 //! JSON schema document.
IanBenzMaxim 0:33d4e66780c0 1312 /*!
IanBenzMaxim 0:33d4e66780c0 1313 A JSON schema document is a compiled version of a JSON schema.
IanBenzMaxim 0:33d4e66780c0 1314 It is basically a tree of internal::Schema.
IanBenzMaxim 0:33d4e66780c0 1315
IanBenzMaxim 0:33d4e66780c0 1316 \note This is an immutable class (i.e. its instance cannot be modified after construction).
IanBenzMaxim 0:33d4e66780c0 1317 \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
IanBenzMaxim 0:33d4e66780c0 1318 \tparam Allocator Allocator type for allocating memory of this document.
IanBenzMaxim 0:33d4e66780c0 1319 */
IanBenzMaxim 0:33d4e66780c0 1320 template <typename ValueT, typename Allocator = CrtAllocator>
IanBenzMaxim 0:33d4e66780c0 1321 class GenericSchemaDocument {
IanBenzMaxim 0:33d4e66780c0 1322 public:
IanBenzMaxim 0:33d4e66780c0 1323 typedef ValueT ValueType;
IanBenzMaxim 0:33d4e66780c0 1324 typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
IanBenzMaxim 0:33d4e66780c0 1325 typedef Allocator AllocatorType;
IanBenzMaxim 0:33d4e66780c0 1326 typedef typename ValueType::EncodingType EncodingType;
IanBenzMaxim 0:33d4e66780c0 1327 typedef typename EncodingType::Ch Ch;
IanBenzMaxim 0:33d4e66780c0 1328 typedef internal::Schema<GenericSchemaDocument> SchemaType;
IanBenzMaxim 0:33d4e66780c0 1329 typedef GenericPointer<ValueType, Allocator> PointerType;
IanBenzMaxim 0:33d4e66780c0 1330 friend class internal::Schema<GenericSchemaDocument>;
IanBenzMaxim 0:33d4e66780c0 1331 template <typename, typename, typename>
IanBenzMaxim 0:33d4e66780c0 1332 friend class GenericSchemaValidator;
IanBenzMaxim 0:33d4e66780c0 1333
IanBenzMaxim 0:33d4e66780c0 1334 //! Constructor.
IanBenzMaxim 0:33d4e66780c0 1335 /*!
IanBenzMaxim 0:33d4e66780c0 1336 Compile a JSON document into schema document.
IanBenzMaxim 0:33d4e66780c0 1337
IanBenzMaxim 0:33d4e66780c0 1338 \param document A JSON document as source.
IanBenzMaxim 0:33d4e66780c0 1339 \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
IanBenzMaxim 0:33d4e66780c0 1340 \param allocator An optional allocator instance for allocating memory. Can be null.
IanBenzMaxim 0:33d4e66780c0 1341 */
IanBenzMaxim 0:33d4e66780c0 1342 explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
IanBenzMaxim 0:33d4e66780c0 1343 remoteProvider_(remoteProvider),
IanBenzMaxim 0:33d4e66780c0 1344 allocator_(allocator),
IanBenzMaxim 0:33d4e66780c0 1345 ownAllocator_(),
IanBenzMaxim 0:33d4e66780c0 1346 root_(),
IanBenzMaxim 0:33d4e66780c0 1347 schemaMap_(allocator, kInitialSchemaMapSize),
IanBenzMaxim 0:33d4e66780c0 1348 schemaRef_(allocator, kInitialSchemaRefSize)
IanBenzMaxim 0:33d4e66780c0 1349 {
IanBenzMaxim 0:33d4e66780c0 1350 if (!allocator_)
IanBenzMaxim 0:33d4e66780c0 1351 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
IanBenzMaxim 0:33d4e66780c0 1352
IanBenzMaxim 0:33d4e66780c0 1353 // Generate root schema, it will call CreateSchema() to create sub-schemas,
IanBenzMaxim 0:33d4e66780c0 1354 // And call AddRefSchema() if there are $ref.
IanBenzMaxim 0:33d4e66780c0 1355 CreateSchemaRecursive(&root_, PointerType(), document, document);
IanBenzMaxim 0:33d4e66780c0 1356
IanBenzMaxim 0:33d4e66780c0 1357 // Resolve $ref
IanBenzMaxim 0:33d4e66780c0 1358 while (!schemaRef_.Empty()) {
IanBenzMaxim 0:33d4e66780c0 1359 SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
IanBenzMaxim 0:33d4e66780c0 1360 if (const SchemaType* s = GetSchema(refEntry->target)) {
IanBenzMaxim 0:33d4e66780c0 1361 if (refEntry->schema)
IanBenzMaxim 0:33d4e66780c0 1362 *refEntry->schema = s;
IanBenzMaxim 0:33d4e66780c0 1363
IanBenzMaxim 0:33d4e66780c0 1364 // Create entry in map if not exist
IanBenzMaxim 0:33d4e66780c0 1365 if (!GetSchema(refEntry->source)) {
IanBenzMaxim 0:33d4e66780c0 1366 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
IanBenzMaxim 0:33d4e66780c0 1367 }
IanBenzMaxim 0:33d4e66780c0 1368 }
IanBenzMaxim 0:33d4e66780c0 1369 refEntry->~SchemaRefEntry();
IanBenzMaxim 0:33d4e66780c0 1370 }
IanBenzMaxim 0:33d4e66780c0 1371
IanBenzMaxim 0:33d4e66780c0 1372 RAPIDJSON_ASSERT(root_ != 0);
IanBenzMaxim 0:33d4e66780c0 1373
IanBenzMaxim 0:33d4e66780c0 1374 schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
IanBenzMaxim 0:33d4e66780c0 1375 }
IanBenzMaxim 0:33d4e66780c0 1376
IanBenzMaxim 0:33d4e66780c0 1377 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
IanBenzMaxim 0:33d4e66780c0 1378 //! Move constructor in C++11
IanBenzMaxim 0:33d4e66780c0 1379 GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
IanBenzMaxim 0:33d4e66780c0 1380 remoteProvider_(rhs.remoteProvider_),
IanBenzMaxim 0:33d4e66780c0 1381 allocator_(rhs.allocator_),
IanBenzMaxim 0:33d4e66780c0 1382 ownAllocator_(rhs.ownAllocator_),
IanBenzMaxim 0:33d4e66780c0 1383 root_(rhs.root_),
IanBenzMaxim 0:33d4e66780c0 1384 schemaMap_(std::move(rhs.schemaMap_)),
IanBenzMaxim 0:33d4e66780c0 1385 schemaRef_(std::move(rhs.schemaRef_))
IanBenzMaxim 0:33d4e66780c0 1386 {
IanBenzMaxim 0:33d4e66780c0 1387 rhs.remoteProvider_ = 0;
IanBenzMaxim 0:33d4e66780c0 1388 rhs.allocator_ = 0;
IanBenzMaxim 0:33d4e66780c0 1389 rhs.ownAllocator_ = 0;
IanBenzMaxim 0:33d4e66780c0 1390 }
IanBenzMaxim 0:33d4e66780c0 1391 #endif
IanBenzMaxim 0:33d4e66780c0 1392
IanBenzMaxim 0:33d4e66780c0 1393 //! Destructor
IanBenzMaxim 0:33d4e66780c0 1394 ~GenericSchemaDocument() {
IanBenzMaxim 0:33d4e66780c0 1395 while (!schemaMap_.Empty())
IanBenzMaxim 0:33d4e66780c0 1396 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
IanBenzMaxim 0:33d4e66780c0 1397
IanBenzMaxim 0:33d4e66780c0 1398 RAPIDJSON_DELETE(ownAllocator_);
IanBenzMaxim 0:33d4e66780c0 1399 }
IanBenzMaxim 0:33d4e66780c0 1400
IanBenzMaxim 0:33d4e66780c0 1401 //! Get the root schema.
IanBenzMaxim 0:33d4e66780c0 1402 const SchemaType& GetRoot() const { return *root_; }
IanBenzMaxim 0:33d4e66780c0 1403
IanBenzMaxim 0:33d4e66780c0 1404 private:
IanBenzMaxim 0:33d4e66780c0 1405 //! Prohibit copying
IanBenzMaxim 0:33d4e66780c0 1406 GenericSchemaDocument(const GenericSchemaDocument&);
IanBenzMaxim 0:33d4e66780c0 1407 //! Prohibit assignment
IanBenzMaxim 0:33d4e66780c0 1408 GenericSchemaDocument& operator=(const GenericSchemaDocument&);
IanBenzMaxim 0:33d4e66780c0 1409
IanBenzMaxim 0:33d4e66780c0 1410 struct SchemaRefEntry {
IanBenzMaxim 0:33d4e66780c0 1411 SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
IanBenzMaxim 0:33d4e66780c0 1412 PointerType source;
IanBenzMaxim 0:33d4e66780c0 1413 PointerType target;
IanBenzMaxim 0:33d4e66780c0 1414 const SchemaType** schema;
IanBenzMaxim 0:33d4e66780c0 1415 };
IanBenzMaxim 0:33d4e66780c0 1416
IanBenzMaxim 0:33d4e66780c0 1417 struct SchemaEntry {
IanBenzMaxim 0:33d4e66780c0 1418 SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
IanBenzMaxim 0:33d4e66780c0 1419 ~SchemaEntry() {
IanBenzMaxim 0:33d4e66780c0 1420 if (owned) {
IanBenzMaxim 0:33d4e66780c0 1421 schema->~SchemaType();
IanBenzMaxim 0:33d4e66780c0 1422 Allocator::Free(schema);
IanBenzMaxim 0:33d4e66780c0 1423 }
IanBenzMaxim 0:33d4e66780c0 1424 }
IanBenzMaxim 0:33d4e66780c0 1425 PointerType pointer;
IanBenzMaxim 0:33d4e66780c0 1426 SchemaType* schema;
IanBenzMaxim 0:33d4e66780c0 1427 bool owned;
IanBenzMaxim 0:33d4e66780c0 1428 };
IanBenzMaxim 0:33d4e66780c0 1429
IanBenzMaxim 0:33d4e66780c0 1430 void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
IanBenzMaxim 0:33d4e66780c0 1431 if (schema)
IanBenzMaxim 0:33d4e66780c0 1432 *schema = SchemaType::GetTypeless();
IanBenzMaxim 0:33d4e66780c0 1433
IanBenzMaxim 0:33d4e66780c0 1434 if (v.GetType() == kObjectType) {
IanBenzMaxim 0:33d4e66780c0 1435 const SchemaType* s = GetSchema(pointer);
IanBenzMaxim 0:33d4e66780c0 1436 if (!s)
IanBenzMaxim 0:33d4e66780c0 1437 CreateSchema(schema, pointer, v, document);
IanBenzMaxim 0:33d4e66780c0 1438
IanBenzMaxim 0:33d4e66780c0 1439 for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
IanBenzMaxim 0:33d4e66780c0 1440 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
IanBenzMaxim 0:33d4e66780c0 1441 }
IanBenzMaxim 0:33d4e66780c0 1442 else if (v.GetType() == kArrayType)
IanBenzMaxim 0:33d4e66780c0 1443 for (SizeType i = 0; i < v.Size(); i++)
IanBenzMaxim 0:33d4e66780c0 1444 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
IanBenzMaxim 0:33d4e66780c0 1445 }
IanBenzMaxim 0:33d4e66780c0 1446
IanBenzMaxim 0:33d4e66780c0 1447 void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
IanBenzMaxim 0:33d4e66780c0 1448 RAPIDJSON_ASSERT(pointer.IsValid());
IanBenzMaxim 0:33d4e66780c0 1449 if (v.IsObject()) {
IanBenzMaxim 0:33d4e66780c0 1450 if (!HandleRefSchema(pointer, schema, v, document)) {
IanBenzMaxim 0:33d4e66780c0 1451 SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
IanBenzMaxim 0:33d4e66780c0 1452 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
IanBenzMaxim 0:33d4e66780c0 1453 if (schema)
IanBenzMaxim 0:33d4e66780c0 1454 *schema = s;
IanBenzMaxim 0:33d4e66780c0 1455 }
IanBenzMaxim 0:33d4e66780c0 1456 }
IanBenzMaxim 0:33d4e66780c0 1457 }
IanBenzMaxim 0:33d4e66780c0 1458
IanBenzMaxim 0:33d4e66780c0 1459 bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
IanBenzMaxim 0:33d4e66780c0 1460 static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
IanBenzMaxim 0:33d4e66780c0 1461 static const ValueType kRefValue(kRefString, 4);
IanBenzMaxim 0:33d4e66780c0 1462
IanBenzMaxim 0:33d4e66780c0 1463 typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
IanBenzMaxim 0:33d4e66780c0 1464 if (itr == v.MemberEnd())
IanBenzMaxim 0:33d4e66780c0 1465 return false;
IanBenzMaxim 0:33d4e66780c0 1466
IanBenzMaxim 0:33d4e66780c0 1467 if (itr->value.IsString()) {
IanBenzMaxim 0:33d4e66780c0 1468 SizeType len = itr->value.GetStringLength();
IanBenzMaxim 0:33d4e66780c0 1469 if (len > 0) {
IanBenzMaxim 0:33d4e66780c0 1470 const Ch* s = itr->value.GetString();
IanBenzMaxim 0:33d4e66780c0 1471 SizeType i = 0;
IanBenzMaxim 0:33d4e66780c0 1472 while (i < len && s[i] != '#') // Find the first #
IanBenzMaxim 0:33d4e66780c0 1473 i++;
IanBenzMaxim 0:33d4e66780c0 1474
IanBenzMaxim 0:33d4e66780c0 1475 if (i > 0) { // Remote reference, resolve immediately
IanBenzMaxim 0:33d4e66780c0 1476 if (remoteProvider_) {
IanBenzMaxim 0:33d4e66780c0 1477 if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
IanBenzMaxim 0:33d4e66780c0 1478 PointerType pointer(&s[i], len - i, allocator_);
IanBenzMaxim 0:33d4e66780c0 1479 if (pointer.IsValid()) {
IanBenzMaxim 0:33d4e66780c0 1480 if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
IanBenzMaxim 0:33d4e66780c0 1481 if (schema)
IanBenzMaxim 0:33d4e66780c0 1482 *schema = sc;
IanBenzMaxim 0:33d4e66780c0 1483 return true;
IanBenzMaxim 0:33d4e66780c0 1484 }
IanBenzMaxim 0:33d4e66780c0 1485 }
IanBenzMaxim 0:33d4e66780c0 1486 }
IanBenzMaxim 0:33d4e66780c0 1487 }
IanBenzMaxim 0:33d4e66780c0 1488 }
IanBenzMaxim 0:33d4e66780c0 1489 else if (s[i] == '#') { // Local reference, defer resolution
IanBenzMaxim 0:33d4e66780c0 1490 PointerType pointer(&s[i], len - i, allocator_);
IanBenzMaxim 0:33d4e66780c0 1491 if (pointer.IsValid()) {
IanBenzMaxim 0:33d4e66780c0 1492 if (const ValueType* nv = pointer.Get(document))
IanBenzMaxim 0:33d4e66780c0 1493 if (HandleRefSchema(source, schema, *nv, document))
IanBenzMaxim 0:33d4e66780c0 1494 return true;
IanBenzMaxim 0:33d4e66780c0 1495
IanBenzMaxim 0:33d4e66780c0 1496 new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
IanBenzMaxim 0:33d4e66780c0 1497 return true;
IanBenzMaxim 0:33d4e66780c0 1498 }
IanBenzMaxim 0:33d4e66780c0 1499 }
IanBenzMaxim 0:33d4e66780c0 1500 }
IanBenzMaxim 0:33d4e66780c0 1501 }
IanBenzMaxim 0:33d4e66780c0 1502 return false;
IanBenzMaxim 0:33d4e66780c0 1503 }
IanBenzMaxim 0:33d4e66780c0 1504
IanBenzMaxim 0:33d4e66780c0 1505 const SchemaType* GetSchema(const PointerType& pointer) const {
IanBenzMaxim 0:33d4e66780c0 1506 for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
IanBenzMaxim 0:33d4e66780c0 1507 if (pointer == target->pointer)
IanBenzMaxim 0:33d4e66780c0 1508 return target->schema;
IanBenzMaxim 0:33d4e66780c0 1509 return 0;
IanBenzMaxim 0:33d4e66780c0 1510 }
IanBenzMaxim 0:33d4e66780c0 1511
IanBenzMaxim 0:33d4e66780c0 1512 PointerType GetPointer(const SchemaType* schema) const {
IanBenzMaxim 0:33d4e66780c0 1513 for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
IanBenzMaxim 0:33d4e66780c0 1514 if (schema == target->schema)
IanBenzMaxim 0:33d4e66780c0 1515 return target->pointer;
IanBenzMaxim 0:33d4e66780c0 1516 return PointerType();
IanBenzMaxim 0:33d4e66780c0 1517 }
IanBenzMaxim 0:33d4e66780c0 1518
IanBenzMaxim 0:33d4e66780c0 1519 static const size_t kInitialSchemaMapSize = 64;
IanBenzMaxim 0:33d4e66780c0 1520 static const size_t kInitialSchemaRefSize = 64;
IanBenzMaxim 0:33d4e66780c0 1521
IanBenzMaxim 0:33d4e66780c0 1522 IRemoteSchemaDocumentProviderType* remoteProvider_;
IanBenzMaxim 0:33d4e66780c0 1523 Allocator *allocator_;
IanBenzMaxim 0:33d4e66780c0 1524 Allocator *ownAllocator_;
IanBenzMaxim 0:33d4e66780c0 1525 const SchemaType* root_; //!< Root schema.
IanBenzMaxim 0:33d4e66780c0 1526 internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
IanBenzMaxim 0:33d4e66780c0 1527 internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
IanBenzMaxim 0:33d4e66780c0 1528 };
IanBenzMaxim 0:33d4e66780c0 1529
IanBenzMaxim 0:33d4e66780c0 1530 //! GenericSchemaDocument using Value type.
IanBenzMaxim 0:33d4e66780c0 1531 typedef GenericSchemaDocument<Value> SchemaDocument;
IanBenzMaxim 0:33d4e66780c0 1532 //! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
IanBenzMaxim 0:33d4e66780c0 1533 typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
IanBenzMaxim 0:33d4e66780c0 1534
IanBenzMaxim 0:33d4e66780c0 1535 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 1536 // GenericSchemaValidator
IanBenzMaxim 0:33d4e66780c0 1537
IanBenzMaxim 0:33d4e66780c0 1538 //! JSON Schema Validator.
IanBenzMaxim 0:33d4e66780c0 1539 /*!
IanBenzMaxim 0:33d4e66780c0 1540 A SAX style JSON schema validator.
IanBenzMaxim 0:33d4e66780c0 1541 It uses a \c GenericSchemaDocument to validate SAX events.
IanBenzMaxim 0:33d4e66780c0 1542 It delegates the incoming SAX events to an output handler.
IanBenzMaxim 0:33d4e66780c0 1543 The default output handler does nothing.
IanBenzMaxim 0:33d4e66780c0 1544 It can be reused multiple times by calling \c Reset().
IanBenzMaxim 0:33d4e66780c0 1545
IanBenzMaxim 0:33d4e66780c0 1546 \tparam SchemaDocumentType Type of schema document.
IanBenzMaxim 0:33d4e66780c0 1547 \tparam OutputHandler Type of output handler. Default handler does nothing.
IanBenzMaxim 0:33d4e66780c0 1548 \tparam StateAllocator Allocator for storing the internal validation states.
IanBenzMaxim 0:33d4e66780c0 1549 */
IanBenzMaxim 0:33d4e66780c0 1550 template <
IanBenzMaxim 0:33d4e66780c0 1551 typename SchemaDocumentType,
IanBenzMaxim 0:33d4e66780c0 1552 typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
IanBenzMaxim 0:33d4e66780c0 1553 typename StateAllocator = CrtAllocator>
IanBenzMaxim 0:33d4e66780c0 1554 class GenericSchemaValidator :
IanBenzMaxim 0:33d4e66780c0 1555 public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
IanBenzMaxim 0:33d4e66780c0 1556 public internal::ISchemaValidator
IanBenzMaxim 0:33d4e66780c0 1557 {
IanBenzMaxim 0:33d4e66780c0 1558 public:
IanBenzMaxim 0:33d4e66780c0 1559 typedef typename SchemaDocumentType::SchemaType SchemaType;
IanBenzMaxim 0:33d4e66780c0 1560 typedef typename SchemaDocumentType::PointerType PointerType;
IanBenzMaxim 0:33d4e66780c0 1561 typedef typename SchemaType::EncodingType EncodingType;
IanBenzMaxim 0:33d4e66780c0 1562 typedef typename EncodingType::Ch Ch;
IanBenzMaxim 0:33d4e66780c0 1563
IanBenzMaxim 0:33d4e66780c0 1564 //! Constructor without output handler.
IanBenzMaxim 0:33d4e66780c0 1565 /*!
IanBenzMaxim 0:33d4e66780c0 1566 \param schemaDocument The schema document to conform to.
IanBenzMaxim 0:33d4e66780c0 1567 \param allocator Optional allocator for storing internal validation states.
IanBenzMaxim 0:33d4e66780c0 1568 \param schemaStackCapacity Optional initial capacity of schema path stack.
IanBenzMaxim 0:33d4e66780c0 1569 \param documentStackCapacity Optional initial capacity of document path stack.
IanBenzMaxim 0:33d4e66780c0 1570 */
IanBenzMaxim 0:33d4e66780c0 1571 GenericSchemaValidator(
IanBenzMaxim 0:33d4e66780c0 1572 const SchemaDocumentType& schemaDocument,
IanBenzMaxim 0:33d4e66780c0 1573 StateAllocator* allocator = 0,
IanBenzMaxim 0:33d4e66780c0 1574 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
IanBenzMaxim 0:33d4e66780c0 1575 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
IanBenzMaxim 0:33d4e66780c0 1576 :
IanBenzMaxim 0:33d4e66780c0 1577 schemaDocument_(&schemaDocument),
IanBenzMaxim 0:33d4e66780c0 1578 root_(schemaDocument.GetRoot()),
IanBenzMaxim 0:33d4e66780c0 1579 outputHandler_(GetNullHandler()),
IanBenzMaxim 0:33d4e66780c0 1580 stateAllocator_(allocator),
IanBenzMaxim 0:33d4e66780c0 1581 ownStateAllocator_(0),
IanBenzMaxim 0:33d4e66780c0 1582 schemaStack_(allocator, schemaStackCapacity),
IanBenzMaxim 0:33d4e66780c0 1583 documentStack_(allocator, documentStackCapacity),
IanBenzMaxim 0:33d4e66780c0 1584 valid_(true)
IanBenzMaxim 0:33d4e66780c0 1585 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 1586 , depth_(0)
IanBenzMaxim 0:33d4e66780c0 1587 #endif
IanBenzMaxim 0:33d4e66780c0 1588 {
IanBenzMaxim 0:33d4e66780c0 1589 }
IanBenzMaxim 0:33d4e66780c0 1590
IanBenzMaxim 0:33d4e66780c0 1591 //! Constructor with output handler.
IanBenzMaxim 0:33d4e66780c0 1592 /*!
IanBenzMaxim 0:33d4e66780c0 1593 \param schemaDocument The schema document to conform to.
IanBenzMaxim 0:33d4e66780c0 1594 \param allocator Optional allocator for storing internal validation states.
IanBenzMaxim 0:33d4e66780c0 1595 \param schemaStackCapacity Optional initial capacity of schema path stack.
IanBenzMaxim 0:33d4e66780c0 1596 \param documentStackCapacity Optional initial capacity of document path stack.
IanBenzMaxim 0:33d4e66780c0 1597 */
IanBenzMaxim 0:33d4e66780c0 1598 GenericSchemaValidator(
IanBenzMaxim 0:33d4e66780c0 1599 const SchemaDocumentType& schemaDocument,
IanBenzMaxim 0:33d4e66780c0 1600 OutputHandler& outputHandler,
IanBenzMaxim 0:33d4e66780c0 1601 StateAllocator* allocator = 0,
IanBenzMaxim 0:33d4e66780c0 1602 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
IanBenzMaxim 0:33d4e66780c0 1603 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
IanBenzMaxim 0:33d4e66780c0 1604 :
IanBenzMaxim 0:33d4e66780c0 1605 schemaDocument_(&schemaDocument),
IanBenzMaxim 0:33d4e66780c0 1606 root_(schemaDocument.GetRoot()),
IanBenzMaxim 0:33d4e66780c0 1607 outputHandler_(outputHandler),
IanBenzMaxim 0:33d4e66780c0 1608 stateAllocator_(allocator),
IanBenzMaxim 0:33d4e66780c0 1609 ownStateAllocator_(0),
IanBenzMaxim 0:33d4e66780c0 1610 schemaStack_(allocator, schemaStackCapacity),
IanBenzMaxim 0:33d4e66780c0 1611 documentStack_(allocator, documentStackCapacity),
IanBenzMaxim 0:33d4e66780c0 1612 valid_(true)
IanBenzMaxim 0:33d4e66780c0 1613 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 1614 , depth_(0)
IanBenzMaxim 0:33d4e66780c0 1615 #endif
IanBenzMaxim 0:33d4e66780c0 1616 {
IanBenzMaxim 0:33d4e66780c0 1617 }
IanBenzMaxim 0:33d4e66780c0 1618
IanBenzMaxim 0:33d4e66780c0 1619 //! Destructor.
IanBenzMaxim 0:33d4e66780c0 1620 ~GenericSchemaValidator() {
IanBenzMaxim 0:33d4e66780c0 1621 Reset();
IanBenzMaxim 0:33d4e66780c0 1622 RAPIDJSON_DELETE(ownStateAllocator_);
IanBenzMaxim 0:33d4e66780c0 1623 }
IanBenzMaxim 0:33d4e66780c0 1624
IanBenzMaxim 0:33d4e66780c0 1625 //! Reset the internal states.
IanBenzMaxim 0:33d4e66780c0 1626 void Reset() {
IanBenzMaxim 0:33d4e66780c0 1627 while (!schemaStack_.Empty())
IanBenzMaxim 0:33d4e66780c0 1628 PopSchema();
IanBenzMaxim 0:33d4e66780c0 1629 documentStack_.Clear();
IanBenzMaxim 0:33d4e66780c0 1630 valid_ = true;
IanBenzMaxim 0:33d4e66780c0 1631 }
IanBenzMaxim 0:33d4e66780c0 1632
IanBenzMaxim 0:33d4e66780c0 1633 //! Checks whether the current state is valid.
IanBenzMaxim 0:33d4e66780c0 1634 // Implementation of ISchemaValidator
IanBenzMaxim 0:33d4e66780c0 1635 virtual bool IsValid() const { return valid_; }
IanBenzMaxim 0:33d4e66780c0 1636
IanBenzMaxim 0:33d4e66780c0 1637 //! Gets the JSON pointer pointed to the invalid schema.
IanBenzMaxim 0:33d4e66780c0 1638 PointerType GetInvalidSchemaPointer() const {
IanBenzMaxim 0:33d4e66780c0 1639 return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
IanBenzMaxim 0:33d4e66780c0 1640 }
IanBenzMaxim 0:33d4e66780c0 1641
IanBenzMaxim 0:33d4e66780c0 1642 //! Gets the keyword of invalid schema.
IanBenzMaxim 0:33d4e66780c0 1643 const Ch* GetInvalidSchemaKeyword() const {
IanBenzMaxim 0:33d4e66780c0 1644 return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
IanBenzMaxim 0:33d4e66780c0 1645 }
IanBenzMaxim 0:33d4e66780c0 1646
IanBenzMaxim 0:33d4e66780c0 1647 //! Gets the JSON pointer pointed to the invalid value.
IanBenzMaxim 0:33d4e66780c0 1648 PointerType GetInvalidDocumentPointer() const {
IanBenzMaxim 0:33d4e66780c0 1649 return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
IanBenzMaxim 0:33d4e66780c0 1650 }
IanBenzMaxim 0:33d4e66780c0 1651
IanBenzMaxim 0:33d4e66780c0 1652 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 1653 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
IanBenzMaxim 0:33d4e66780c0 1654 RAPIDJSON_MULTILINEMACRO_BEGIN\
IanBenzMaxim 0:33d4e66780c0 1655 *documentStack_.template Push<Ch>() = '\0';\
IanBenzMaxim 0:33d4e66780c0 1656 documentStack_.template Pop<Ch>(1);\
IanBenzMaxim 0:33d4e66780c0 1657 internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
IanBenzMaxim 0:33d4e66780c0 1658 RAPIDJSON_MULTILINEMACRO_END
IanBenzMaxim 0:33d4e66780c0 1659 #else
IanBenzMaxim 0:33d4e66780c0 1660 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
IanBenzMaxim 0:33d4e66780c0 1661 #endif
IanBenzMaxim 0:33d4e66780c0 1662
IanBenzMaxim 0:33d4e66780c0 1663 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
IanBenzMaxim 0:33d4e66780c0 1664 if (!valid_) return false; \
IanBenzMaxim 0:33d4e66780c0 1665 if (!BeginValue() || !CurrentSchema().method arg1) {\
IanBenzMaxim 0:33d4e66780c0 1666 RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
IanBenzMaxim 0:33d4e66780c0 1667 return valid_ = false;\
IanBenzMaxim 0:33d4e66780c0 1668 }
IanBenzMaxim 0:33d4e66780c0 1669
IanBenzMaxim 0:33d4e66780c0 1670 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
IanBenzMaxim 0:33d4e66780c0 1671 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
IanBenzMaxim 0:33d4e66780c0 1672 if (context->hasher)\
IanBenzMaxim 0:33d4e66780c0 1673 static_cast<HasherType*>(context->hasher)->method arg2;\
IanBenzMaxim 0:33d4e66780c0 1674 if (context->validators)\
IanBenzMaxim 0:33d4e66780c0 1675 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
IanBenzMaxim 0:33d4e66780c0 1676 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
IanBenzMaxim 0:33d4e66780c0 1677 if (context->patternPropertiesValidators)\
IanBenzMaxim 0:33d4e66780c0 1678 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
IanBenzMaxim 0:33d4e66780c0 1679 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
IanBenzMaxim 0:33d4e66780c0 1680 }
IanBenzMaxim 0:33d4e66780c0 1681
IanBenzMaxim 0:33d4e66780c0 1682 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
IanBenzMaxim 0:33d4e66780c0 1683 return valid_ = EndValue() && outputHandler_.method arg2
IanBenzMaxim 0:33d4e66780c0 1684
IanBenzMaxim 0:33d4e66780c0 1685 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
IanBenzMaxim 0:33d4e66780c0 1686 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
IanBenzMaxim 0:33d4e66780c0 1687 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
IanBenzMaxim 0:33d4e66780c0 1688 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
IanBenzMaxim 0:33d4e66780c0 1689
IanBenzMaxim 0:33d4e66780c0 1690 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
IanBenzMaxim 0:33d4e66780c0 1691 bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
IanBenzMaxim 0:33d4e66780c0 1692 bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
IanBenzMaxim 0:33d4e66780c0 1693 bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
IanBenzMaxim 0:33d4e66780c0 1694 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
IanBenzMaxim 0:33d4e66780c0 1695 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
IanBenzMaxim 0:33d4e66780c0 1696 bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
IanBenzMaxim 0:33d4e66780c0 1697 bool RawNumber(const Ch* str, SizeType length, bool copy)
IanBenzMaxim 0:33d4e66780c0 1698 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
IanBenzMaxim 0:33d4e66780c0 1699 bool String(const Ch* str, SizeType length, bool copy)
IanBenzMaxim 0:33d4e66780c0 1700 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
IanBenzMaxim 0:33d4e66780c0 1701
IanBenzMaxim 0:33d4e66780c0 1702 bool StartObject() {
IanBenzMaxim 0:33d4e66780c0 1703 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
IanBenzMaxim 0:33d4e66780c0 1704 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
IanBenzMaxim 0:33d4e66780c0 1705 return valid_ = outputHandler_.StartObject();
IanBenzMaxim 0:33d4e66780c0 1706 }
IanBenzMaxim 0:33d4e66780c0 1707
IanBenzMaxim 0:33d4e66780c0 1708 bool Key(const Ch* str, SizeType len, bool copy) {
IanBenzMaxim 0:33d4e66780c0 1709 if (!valid_) return false;
IanBenzMaxim 0:33d4e66780c0 1710 AppendToken(str, len);
IanBenzMaxim 0:33d4e66780c0 1711 if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
IanBenzMaxim 0:33d4e66780c0 1712 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
IanBenzMaxim 0:33d4e66780c0 1713 return valid_ = outputHandler_.Key(str, len, copy);
IanBenzMaxim 0:33d4e66780c0 1714 }
IanBenzMaxim 0:33d4e66780c0 1715
IanBenzMaxim 0:33d4e66780c0 1716 bool EndObject(SizeType memberCount) {
IanBenzMaxim 0:33d4e66780c0 1717 if (!valid_) return false;
IanBenzMaxim 0:33d4e66780c0 1718 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
IanBenzMaxim 0:33d4e66780c0 1719 if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
IanBenzMaxim 0:33d4e66780c0 1720 RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
IanBenzMaxim 0:33d4e66780c0 1721 }
IanBenzMaxim 0:33d4e66780c0 1722
IanBenzMaxim 0:33d4e66780c0 1723 bool StartArray() {
IanBenzMaxim 0:33d4e66780c0 1724 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
IanBenzMaxim 0:33d4e66780c0 1725 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
IanBenzMaxim 0:33d4e66780c0 1726 return valid_ = outputHandler_.StartArray();
IanBenzMaxim 0:33d4e66780c0 1727 }
IanBenzMaxim 0:33d4e66780c0 1728
IanBenzMaxim 0:33d4e66780c0 1729 bool EndArray(SizeType elementCount) {
IanBenzMaxim 0:33d4e66780c0 1730 if (!valid_) return false;
IanBenzMaxim 0:33d4e66780c0 1731 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
IanBenzMaxim 0:33d4e66780c0 1732 if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
IanBenzMaxim 0:33d4e66780c0 1733 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
IanBenzMaxim 0:33d4e66780c0 1734 }
IanBenzMaxim 0:33d4e66780c0 1735
IanBenzMaxim 0:33d4e66780c0 1736 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
IanBenzMaxim 0:33d4e66780c0 1737 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
IanBenzMaxim 0:33d4e66780c0 1738 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
IanBenzMaxim 0:33d4e66780c0 1739 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
IanBenzMaxim 0:33d4e66780c0 1740
IanBenzMaxim 0:33d4e66780c0 1741 // Implementation of ISchemaStateFactory<SchemaType>
IanBenzMaxim 0:33d4e66780c0 1742 virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
IanBenzMaxim 0:33d4e66780c0 1743 return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
IanBenzMaxim 0:33d4e66780c0 1744 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 1745 depth_ + 1,
IanBenzMaxim 0:33d4e66780c0 1746 #endif
IanBenzMaxim 0:33d4e66780c0 1747 &GetStateAllocator());
IanBenzMaxim 0:33d4e66780c0 1748 }
IanBenzMaxim 0:33d4e66780c0 1749
IanBenzMaxim 0:33d4e66780c0 1750 virtual void DestroySchemaValidator(ISchemaValidator* validator) {
IanBenzMaxim 0:33d4e66780c0 1751 GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
IanBenzMaxim 0:33d4e66780c0 1752 v->~GenericSchemaValidator();
IanBenzMaxim 0:33d4e66780c0 1753 StateAllocator::Free(v);
IanBenzMaxim 0:33d4e66780c0 1754 }
IanBenzMaxim 0:33d4e66780c0 1755
IanBenzMaxim 0:33d4e66780c0 1756 virtual void* CreateHasher() {
IanBenzMaxim 0:33d4e66780c0 1757 return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
IanBenzMaxim 0:33d4e66780c0 1758 }
IanBenzMaxim 0:33d4e66780c0 1759
IanBenzMaxim 0:33d4e66780c0 1760 virtual uint64_t GetHashCode(void* hasher) {
IanBenzMaxim 0:33d4e66780c0 1761 return static_cast<HasherType*>(hasher)->GetHashCode();
IanBenzMaxim 0:33d4e66780c0 1762 }
IanBenzMaxim 0:33d4e66780c0 1763
IanBenzMaxim 0:33d4e66780c0 1764 virtual void DestroryHasher(void* hasher) {
IanBenzMaxim 0:33d4e66780c0 1765 HasherType* h = static_cast<HasherType*>(hasher);
IanBenzMaxim 0:33d4e66780c0 1766 h->~HasherType();
IanBenzMaxim 0:33d4e66780c0 1767 StateAllocator::Free(h);
IanBenzMaxim 0:33d4e66780c0 1768 }
IanBenzMaxim 0:33d4e66780c0 1769
IanBenzMaxim 0:33d4e66780c0 1770 virtual void* MallocState(size_t size) {
IanBenzMaxim 0:33d4e66780c0 1771 return GetStateAllocator().Malloc(size);
IanBenzMaxim 0:33d4e66780c0 1772 }
IanBenzMaxim 0:33d4e66780c0 1773
IanBenzMaxim 0:33d4e66780c0 1774 virtual void FreeState(void* p) {
IanBenzMaxim 0:33d4e66780c0 1775 return StateAllocator::Free(p);
IanBenzMaxim 0:33d4e66780c0 1776 }
IanBenzMaxim 0:33d4e66780c0 1777
IanBenzMaxim 0:33d4e66780c0 1778 private:
IanBenzMaxim 0:33d4e66780c0 1779 typedef typename SchemaType::Context Context;
IanBenzMaxim 0:33d4e66780c0 1780 typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
IanBenzMaxim 0:33d4e66780c0 1781 typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
IanBenzMaxim 0:33d4e66780c0 1782
IanBenzMaxim 0:33d4e66780c0 1783 GenericSchemaValidator(
IanBenzMaxim 0:33d4e66780c0 1784 const SchemaDocumentType& schemaDocument,
IanBenzMaxim 0:33d4e66780c0 1785 const SchemaType& root,
IanBenzMaxim 0:33d4e66780c0 1786 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 1787 unsigned depth,
IanBenzMaxim 0:33d4e66780c0 1788 #endif
IanBenzMaxim 0:33d4e66780c0 1789 StateAllocator* allocator = 0,
IanBenzMaxim 0:33d4e66780c0 1790 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
IanBenzMaxim 0:33d4e66780c0 1791 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
IanBenzMaxim 0:33d4e66780c0 1792 :
IanBenzMaxim 0:33d4e66780c0 1793 schemaDocument_(&schemaDocument),
IanBenzMaxim 0:33d4e66780c0 1794 root_(root),
IanBenzMaxim 0:33d4e66780c0 1795 outputHandler_(GetNullHandler()),
IanBenzMaxim 0:33d4e66780c0 1796 stateAllocator_(allocator),
IanBenzMaxim 0:33d4e66780c0 1797 ownStateAllocator_(0),
IanBenzMaxim 0:33d4e66780c0 1798 schemaStack_(allocator, schemaStackCapacity),
IanBenzMaxim 0:33d4e66780c0 1799 documentStack_(allocator, documentStackCapacity),
IanBenzMaxim 0:33d4e66780c0 1800 valid_(true)
IanBenzMaxim 0:33d4e66780c0 1801 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 1802 , depth_(depth)
IanBenzMaxim 0:33d4e66780c0 1803 #endif
IanBenzMaxim 0:33d4e66780c0 1804 {
IanBenzMaxim 0:33d4e66780c0 1805 }
IanBenzMaxim 0:33d4e66780c0 1806
IanBenzMaxim 0:33d4e66780c0 1807 StateAllocator& GetStateAllocator() {
IanBenzMaxim 0:33d4e66780c0 1808 if (!stateAllocator_)
IanBenzMaxim 0:33d4e66780c0 1809 stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator());
IanBenzMaxim 0:33d4e66780c0 1810 return *stateAllocator_;
IanBenzMaxim 0:33d4e66780c0 1811 }
IanBenzMaxim 0:33d4e66780c0 1812
IanBenzMaxim 0:33d4e66780c0 1813 bool BeginValue() {
IanBenzMaxim 0:33d4e66780c0 1814 if (schemaStack_.Empty())
IanBenzMaxim 0:33d4e66780c0 1815 PushSchema(root_);
IanBenzMaxim 0:33d4e66780c0 1816 else {
IanBenzMaxim 0:33d4e66780c0 1817 if (CurrentContext().inArray)
IanBenzMaxim 0:33d4e66780c0 1818 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
IanBenzMaxim 0:33d4e66780c0 1819
IanBenzMaxim 0:33d4e66780c0 1820 if (!CurrentSchema().BeginValue(CurrentContext()))
IanBenzMaxim 0:33d4e66780c0 1821 return false;
IanBenzMaxim 0:33d4e66780c0 1822
IanBenzMaxim 0:33d4e66780c0 1823 SizeType count = CurrentContext().patternPropertiesSchemaCount;
IanBenzMaxim 0:33d4e66780c0 1824 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
IanBenzMaxim 0:33d4e66780c0 1825 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
IanBenzMaxim 0:33d4e66780c0 1826 bool valueUniqueness = CurrentContext().valueUniqueness;
IanBenzMaxim 0:33d4e66780c0 1827 if (CurrentContext().valueSchema)
IanBenzMaxim 0:33d4e66780c0 1828 PushSchema(*CurrentContext().valueSchema);
IanBenzMaxim 0:33d4e66780c0 1829
IanBenzMaxim 0:33d4e66780c0 1830 if (count > 0) {
IanBenzMaxim 0:33d4e66780c0 1831 CurrentContext().objectPatternValidatorType = patternValidatorType;
IanBenzMaxim 0:33d4e66780c0 1832 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
IanBenzMaxim 0:33d4e66780c0 1833 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
IanBenzMaxim 0:33d4e66780c0 1834 va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
IanBenzMaxim 0:33d4e66780c0 1835 for (SizeType i = 0; i < count; i++)
IanBenzMaxim 0:33d4e66780c0 1836 va[validatorCount++] = CreateSchemaValidator(*sa[i]);
IanBenzMaxim 0:33d4e66780c0 1837 }
IanBenzMaxim 0:33d4e66780c0 1838
IanBenzMaxim 0:33d4e66780c0 1839 CurrentContext().arrayUniqueness = valueUniqueness;
IanBenzMaxim 0:33d4e66780c0 1840 }
IanBenzMaxim 0:33d4e66780c0 1841 return true;
IanBenzMaxim 0:33d4e66780c0 1842 }
IanBenzMaxim 0:33d4e66780c0 1843
IanBenzMaxim 0:33d4e66780c0 1844 bool EndValue() {
IanBenzMaxim 0:33d4e66780c0 1845 if (!CurrentSchema().EndValue(CurrentContext()))
IanBenzMaxim 0:33d4e66780c0 1846 return false;
IanBenzMaxim 0:33d4e66780c0 1847
IanBenzMaxim 0:33d4e66780c0 1848 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 1849 GenericStringBuffer<EncodingType> sb;
IanBenzMaxim 0:33d4e66780c0 1850 schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
IanBenzMaxim 0:33d4e66780c0 1851
IanBenzMaxim 0:33d4e66780c0 1852 *documentStack_.template Push<Ch>() = '\0';
IanBenzMaxim 0:33d4e66780c0 1853 documentStack_.template Pop<Ch>(1);
IanBenzMaxim 0:33d4e66780c0 1854 internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
IanBenzMaxim 0:33d4e66780c0 1855 #endif
IanBenzMaxim 0:33d4e66780c0 1856
IanBenzMaxim 0:33d4e66780c0 1857 uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
IanBenzMaxim 0:33d4e66780c0 1858
IanBenzMaxim 0:33d4e66780c0 1859 PopSchema();
IanBenzMaxim 0:33d4e66780c0 1860
IanBenzMaxim 0:33d4e66780c0 1861 if (!schemaStack_.Empty()) {
IanBenzMaxim 0:33d4e66780c0 1862 Context& context = CurrentContext();
IanBenzMaxim 0:33d4e66780c0 1863 if (context.valueUniqueness) {
IanBenzMaxim 0:33d4e66780c0 1864 HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
IanBenzMaxim 0:33d4e66780c0 1865 if (!a)
IanBenzMaxim 0:33d4e66780c0 1866 CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
IanBenzMaxim 0:33d4e66780c0 1867 for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
IanBenzMaxim 0:33d4e66780c0 1868 if (itr->GetUint64() == h)
IanBenzMaxim 0:33d4e66780c0 1869 RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
IanBenzMaxim 0:33d4e66780c0 1870 a->PushBack(h, GetStateAllocator());
IanBenzMaxim 0:33d4e66780c0 1871 }
IanBenzMaxim 0:33d4e66780c0 1872 }
IanBenzMaxim 0:33d4e66780c0 1873
IanBenzMaxim 0:33d4e66780c0 1874 // Remove the last token of document pointer
IanBenzMaxim 0:33d4e66780c0 1875 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
IanBenzMaxim 0:33d4e66780c0 1876 ;
IanBenzMaxim 0:33d4e66780c0 1877
IanBenzMaxim 0:33d4e66780c0 1878 return true;
IanBenzMaxim 0:33d4e66780c0 1879 }
IanBenzMaxim 0:33d4e66780c0 1880
IanBenzMaxim 0:33d4e66780c0 1881 void AppendToken(const Ch* str, SizeType len) {
IanBenzMaxim 0:33d4e66780c0 1882 documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
IanBenzMaxim 0:33d4e66780c0 1883 *documentStack_.template PushUnsafe<Ch>() = '/';
IanBenzMaxim 0:33d4e66780c0 1884 for (SizeType i = 0; i < len; i++) {
IanBenzMaxim 0:33d4e66780c0 1885 if (str[i] == '~') {
IanBenzMaxim 0:33d4e66780c0 1886 *documentStack_.template PushUnsafe<Ch>() = '~';
IanBenzMaxim 0:33d4e66780c0 1887 *documentStack_.template PushUnsafe<Ch>() = '0';
IanBenzMaxim 0:33d4e66780c0 1888 }
IanBenzMaxim 0:33d4e66780c0 1889 else if (str[i] == '/') {
IanBenzMaxim 0:33d4e66780c0 1890 *documentStack_.template PushUnsafe<Ch>() = '~';
IanBenzMaxim 0:33d4e66780c0 1891 *documentStack_.template PushUnsafe<Ch>() = '1';
IanBenzMaxim 0:33d4e66780c0 1892 }
IanBenzMaxim 0:33d4e66780c0 1893 else
IanBenzMaxim 0:33d4e66780c0 1894 *documentStack_.template PushUnsafe<Ch>() = str[i];
IanBenzMaxim 0:33d4e66780c0 1895 }
IanBenzMaxim 0:33d4e66780c0 1896 }
IanBenzMaxim 0:33d4e66780c0 1897
IanBenzMaxim 0:33d4e66780c0 1898 RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
IanBenzMaxim 0:33d4e66780c0 1899
IanBenzMaxim 0:33d4e66780c0 1900 RAPIDJSON_FORCEINLINE void PopSchema() {
IanBenzMaxim 0:33d4e66780c0 1901 Context* c = schemaStack_.template Pop<Context>(1);
IanBenzMaxim 0:33d4e66780c0 1902 if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
IanBenzMaxim 0:33d4e66780c0 1903 a->~HashCodeArray();
IanBenzMaxim 0:33d4e66780c0 1904 StateAllocator::Free(a);
IanBenzMaxim 0:33d4e66780c0 1905 }
IanBenzMaxim 0:33d4e66780c0 1906 c->~Context();
IanBenzMaxim 0:33d4e66780c0 1907 }
IanBenzMaxim 0:33d4e66780c0 1908
IanBenzMaxim 0:33d4e66780c0 1909 const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
IanBenzMaxim 0:33d4e66780c0 1910 Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
IanBenzMaxim 0:33d4e66780c0 1911 const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
IanBenzMaxim 0:33d4e66780c0 1912
IanBenzMaxim 0:33d4e66780c0 1913 static OutputHandler& GetNullHandler() {
IanBenzMaxim 0:33d4e66780c0 1914 static OutputHandler nullHandler;
IanBenzMaxim 0:33d4e66780c0 1915 return nullHandler;
IanBenzMaxim 0:33d4e66780c0 1916 }
IanBenzMaxim 0:33d4e66780c0 1917
IanBenzMaxim 0:33d4e66780c0 1918 static const size_t kDefaultSchemaStackCapacity = 1024;
IanBenzMaxim 0:33d4e66780c0 1919 static const size_t kDefaultDocumentStackCapacity = 256;
IanBenzMaxim 0:33d4e66780c0 1920 const SchemaDocumentType* schemaDocument_;
IanBenzMaxim 0:33d4e66780c0 1921 const SchemaType& root_;
IanBenzMaxim 0:33d4e66780c0 1922 OutputHandler& outputHandler_;
IanBenzMaxim 0:33d4e66780c0 1923 StateAllocator* stateAllocator_;
IanBenzMaxim 0:33d4e66780c0 1924 StateAllocator* ownStateAllocator_;
IanBenzMaxim 0:33d4e66780c0 1925 internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
IanBenzMaxim 0:33d4e66780c0 1926 internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch)
IanBenzMaxim 0:33d4e66780c0 1927 bool valid_;
IanBenzMaxim 0:33d4e66780c0 1928 #if RAPIDJSON_SCHEMA_VERBOSE
IanBenzMaxim 0:33d4e66780c0 1929 unsigned depth_;
IanBenzMaxim 0:33d4e66780c0 1930 #endif
IanBenzMaxim 0:33d4e66780c0 1931 };
IanBenzMaxim 0:33d4e66780c0 1932
IanBenzMaxim 0:33d4e66780c0 1933 typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
IanBenzMaxim 0:33d4e66780c0 1934
IanBenzMaxim 0:33d4e66780c0 1935 ///////////////////////////////////////////////////////////////////////////////
IanBenzMaxim 0:33d4e66780c0 1936 // SchemaValidatingReader
IanBenzMaxim 0:33d4e66780c0 1937
IanBenzMaxim 0:33d4e66780c0 1938 //! A helper class for parsing with validation.
IanBenzMaxim 0:33d4e66780c0 1939 /*!
IanBenzMaxim 0:33d4e66780c0 1940 This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
IanBenzMaxim 0:33d4e66780c0 1941
IanBenzMaxim 0:33d4e66780c0 1942 \tparam parseFlags Combination of \ref ParseFlag.
IanBenzMaxim 0:33d4e66780c0 1943 \tparam InputStream Type of input stream, implementing Stream concept.
IanBenzMaxim 0:33d4e66780c0 1944 \tparam SourceEncoding Encoding of the input stream.
IanBenzMaxim 0:33d4e66780c0 1945 \tparam SchemaDocumentType Type of schema document.
IanBenzMaxim 0:33d4e66780c0 1946 \tparam StackAllocator Allocator type for stack.
IanBenzMaxim 0:33d4e66780c0 1947 */
IanBenzMaxim 0:33d4e66780c0 1948 template <
IanBenzMaxim 0:33d4e66780c0 1949 unsigned parseFlags,
IanBenzMaxim 0:33d4e66780c0 1950 typename InputStream,
IanBenzMaxim 0:33d4e66780c0 1951 typename SourceEncoding,
IanBenzMaxim 0:33d4e66780c0 1952 typename SchemaDocumentType = SchemaDocument,
IanBenzMaxim 0:33d4e66780c0 1953 typename StackAllocator = CrtAllocator>
IanBenzMaxim 0:33d4e66780c0 1954 class SchemaValidatingReader {
IanBenzMaxim 0:33d4e66780c0 1955 public:
IanBenzMaxim 0:33d4e66780c0 1956 typedef typename SchemaDocumentType::PointerType PointerType;
IanBenzMaxim 0:33d4e66780c0 1957 typedef typename InputStream::Ch Ch;
IanBenzMaxim 0:33d4e66780c0 1958
IanBenzMaxim 0:33d4e66780c0 1959 //! Constructor
IanBenzMaxim 0:33d4e66780c0 1960 /*!
IanBenzMaxim 0:33d4e66780c0 1961 \param is Input stream.
IanBenzMaxim 0:33d4e66780c0 1962 \param sd Schema document.
IanBenzMaxim 0:33d4e66780c0 1963 */
IanBenzMaxim 0:33d4e66780c0 1964 SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
IanBenzMaxim 0:33d4e66780c0 1965
IanBenzMaxim 0:33d4e66780c0 1966 template <typename Handler>
IanBenzMaxim 0:33d4e66780c0 1967 bool operator()(Handler& handler) {
IanBenzMaxim 0:33d4e66780c0 1968 GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
IanBenzMaxim 0:33d4e66780c0 1969 GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
IanBenzMaxim 0:33d4e66780c0 1970 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
IanBenzMaxim 0:33d4e66780c0 1971
IanBenzMaxim 0:33d4e66780c0 1972 isValid_ = validator.IsValid();
IanBenzMaxim 0:33d4e66780c0 1973 if (isValid_) {
IanBenzMaxim 0:33d4e66780c0 1974 invalidSchemaPointer_ = PointerType();
IanBenzMaxim 0:33d4e66780c0 1975 invalidSchemaKeyword_ = 0;
IanBenzMaxim 0:33d4e66780c0 1976 invalidDocumentPointer_ = PointerType();
IanBenzMaxim 0:33d4e66780c0 1977 }
IanBenzMaxim 0:33d4e66780c0 1978 else {
IanBenzMaxim 0:33d4e66780c0 1979 invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
IanBenzMaxim 0:33d4e66780c0 1980 invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
IanBenzMaxim 0:33d4e66780c0 1981 invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
IanBenzMaxim 0:33d4e66780c0 1982 }
IanBenzMaxim 0:33d4e66780c0 1983
IanBenzMaxim 0:33d4e66780c0 1984 return parseResult_;
IanBenzMaxim 0:33d4e66780c0 1985 }
IanBenzMaxim 0:33d4e66780c0 1986
IanBenzMaxim 0:33d4e66780c0 1987 const ParseResult& GetParseResult() const { return parseResult_; }
IanBenzMaxim 0:33d4e66780c0 1988 bool IsValid() const { return isValid_; }
IanBenzMaxim 0:33d4e66780c0 1989 const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
IanBenzMaxim 0:33d4e66780c0 1990 const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
IanBenzMaxim 0:33d4e66780c0 1991 const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
IanBenzMaxim 0:33d4e66780c0 1992
IanBenzMaxim 0:33d4e66780c0 1993 private:
IanBenzMaxim 0:33d4e66780c0 1994 InputStream& is_;
IanBenzMaxim 0:33d4e66780c0 1995 const SchemaDocumentType& sd_;
IanBenzMaxim 0:33d4e66780c0 1996
IanBenzMaxim 0:33d4e66780c0 1997 ParseResult parseResult_;
IanBenzMaxim 0:33d4e66780c0 1998 PointerType invalidSchemaPointer_;
IanBenzMaxim 0:33d4e66780c0 1999 const Ch* invalidSchemaKeyword_;
IanBenzMaxim 0:33d4e66780c0 2000 PointerType invalidDocumentPointer_;
IanBenzMaxim 0:33d4e66780c0 2001 bool isValid_;
IanBenzMaxim 0:33d4e66780c0 2002 };
IanBenzMaxim 0:33d4e66780c0 2003
IanBenzMaxim 0:33d4e66780c0 2004 RAPIDJSON_NAMESPACE_END
IanBenzMaxim 0:33d4e66780c0 2005 RAPIDJSON_DIAG_POP
IanBenzMaxim 0:33d4e66780c0 2006
IanBenzMaxim 0:33d4e66780c0 2007 #endif // RAPIDJSON_SCHEMA_H_