diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h
index 12187ea..59cdca1 100644
--- a/include/rapidjson/document.h
+++ b/include/rapidjson/document.h
@@ -1869,6 +1869,21 @@ public:
*/
friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+ //! Populate this document by a generator which produces SAX events.
+ /*! \tparam Generator A functor with bool f(Handler) prototype.
+ \param g Generator functor which sends SAX events to the parameter.
+ \return The document itself for fluent API.
+ */
+ template
+ GenericDocument& Populate(Generator& g) {
+ ClearStackOnExit scope(*this);
+ if (g(*this)) {
+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+ ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document
+ }
+ return *this;
+ }
+
//!@name Parse from stream
//!@{
@@ -2017,9 +2032,10 @@ private:
};
// callers of the following private Handler functions
- template friend class GenericReader; // for parsing
+ // template friend class GenericReader; // for parsing
template friend class GenericValue; // for deep copying
+public:
// Implementation of Handler
bool Null() { new (stack_.template Push()) ValueType(); return true; }
bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; }
diff --git a/include/rapidjson/internal/regex.h b/include/rapidjson/internal/regex.h
index f3333b2..5c82fb4 100644
--- a/include/rapidjson/internal/regex.h
+++ b/include/rapidjson/internal/regex.h
@@ -18,6 +18,12 @@
#include "../rapidjson.h"
#include "stack.h"
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+#endif
+
#ifndef RAPIDJSON_REGEX_VERBOSE
#define RAPIDJSON_REGEX_VERBOSE 0
#endif
@@ -639,4 +645,8 @@ typedef GenericRegex > Regex;
} // namespace internal
RAPIDJSON_NAMESPACE_END
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
#endif // RAPIDJSON_INTERNAL_REGEX_H_
diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h
index fda3bf6..6bb3a35 100644
--- a/include/rapidjson/schema.h
+++ b/include/rapidjson/schema.h
@@ -19,6 +19,12 @@
#include "pointer.h"
#include // HUGE_VAL, abs, floor
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(weak-vtables)
+RAPIDJSON_DIAG_OFF(exit-time-destructors)
+#endif
+
#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
#else
@@ -56,6 +62,11 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(variadic-macros)
+#endif
+
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
@@ -865,39 +876,39 @@ public:
return v;\
}
- RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l');
- RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n');
- RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't');
- RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y');
- RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g');
- RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r');
- RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r');
- RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e');
- RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm');
- RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f');
- RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f');
- RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f');
- RAPIDJSON_STRING_(Not, 'n', 'o', 't');
- RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
- RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd');
- RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's');
- RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
- RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
- RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
- RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
- RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's');
- RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's');
- RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's');
- RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's');
- RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's');
- RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h');
- RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h');
- RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n');
- RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm');
- RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm');
- RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm');
- RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm');
- RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f');
+ RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
+ RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
+ RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
+ RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
+ RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
+ RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
+ RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
+ RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
+ RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
+ RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
+ RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
+ RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
+ RAPIDJSON_STRING_(Not, 'n', 'o', 't')
+ RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
+ RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
+ RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+ RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
+ RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
+ RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
+ RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
#undef RAPIDJSON_STRING_
@@ -1380,9 +1391,9 @@ private:
if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) {
PointerType pointer(&s[i], len - i, allocator_);
if (pointer.IsValid()) {
- if (const SchemaType* s = remoteDocument->GetSchema(pointer)) {
+ if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
if (schema)
- *schema = s;
+ *schema = sc;
return true;
}
}
@@ -1414,7 +1425,7 @@ private:
PointerType GetPointer(const SchemaType* schema) const {
for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target)
- if (schema== target->schema)
+ if (schema == target->schema)
return target->pointer;
return PointerType();
}
@@ -1457,13 +1468,39 @@ public:
schemaDocument_(&schemaDocument),
root_(schemaDocument.GetRoot()),
outputHandler_(nullOutputHandler_),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
schemaStack_(allocator, schemaStackCapacity),
- documentStack_(&GetStateAllocator(), documentStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
valid_(true)
#if RAPIDJSON_SCHEMA_VERBOSE
, depth_(0)
#endif
{
+ CreateOwnAllocator();
+ }
+
+ // Constructor with outputHandler
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ OutputHandler& outputHandler,
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ :
+ schemaDocument_(&schemaDocument),
+ root_(schemaDocument.GetRoot()),
+ outputHandler_(outputHandler),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ , depth_(0)
+#endif
+ {
+ CreateOwnAllocator();
}
~GenericSchemaValidator() {
@@ -1475,7 +1512,7 @@ public:
PopSchema();
//documentStack_.Clear();
valid_ = true;
- };
+ }
// Implementation of ISchemaValidator
virtual bool IsValid() const { return valid_; }
@@ -1493,7 +1530,7 @@ public:
}
StateAllocator& GetStateAllocator() {
- return schemaStack_.GetAllocator();
+ return *stateAllocator_;
}
#if RAPIDJSON_SCHEMA_VERBOSE
@@ -1642,6 +1679,8 @@ private:
schemaDocument_(&schemaDocument),
root_(root),
outputHandler_(nullOutputHandler_),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
schemaStack_(allocator, schemaStackCapacity),
documentStack_(allocator, documentStackCapacity),
valid_(true)
@@ -1649,6 +1688,12 @@ private:
, depth_(depth)
#endif
{
+ CreateOwnAllocator();
+ }
+
+ void CreateOwnAllocator() {
+ if (!stateAllocator_)
+ stateAllocator_ = ownStateAllocator_ = new StateAllocator;
}
bool BeginValue() {
@@ -1738,8 +1783,8 @@ private:
void AppendToken(SizeType index) {
*documentStack_.template Push() = '/';
char buffer[21];
- SizeType length = (sizeof(SizeType) == 4 ? internal::u32toa(index, buffer): internal::u64toa(index, buffer)) - buffer;
- for (SizeType i = 0; i < length; i++)
+ size_t length = static_cast((sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer)) - buffer);
+ for (size_t i = 0; i < length; i++)
*documentStack_.template Push() = buffer[i];
}
@@ -1762,8 +1807,10 @@ private:
static const size_t kDefaultDocumentStackCapacity = 256;
const SchemaDocumentType* schemaDocument_;
const SchemaType& root_;
- BaseReaderHandler nullOutputHandler_;
+ OutputHandler nullOutputHandler_;
OutputHandler& outputHandler_;
+ StateAllocator* stateAllocator_;
+ StateAllocator* ownStateAllocator_;
internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch)
bool valid_;
@@ -1774,10 +1821,62 @@ private:
typedef GenericSchemaValidator SchemaValidator;
+template <
+ unsigned parseFlags,
+ typename InputStream,
+ typename SourceEncoding,
+ typename SchemaDocumentType = SchemaDocument,
+ typename StackAllocator = CrtAllocator>
+class SchemaValidatingReader {
+public:
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename InputStream::Ch Ch;
+
+ SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_() {}
+
+ template
+ bool operator()(Handler& handler) {
+ GenericReader reader;
+ GenericSchemaValidator validator(sd_, handler);
+ parseResult_ = reader.template Parse(is_, validator);
+
+ if (validator.IsValid()) {
+ invalidSchemaPointer_ = PointerType();
+ invalidSchemaKeyword_ = 0;
+ invalidDocumentPointer_ = PointerType();
+ }
+ else {
+ invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
+ invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
+ invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
+ }
+
+ return parseResult_;
+ }
+
+ const ParseResult& GetParseResult() const { return parseResult_; }
+ const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
+ const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
+ const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
+
+private:
+ InputStream& is_;
+ const SchemaDocumentType& sd_;
+
+ ParseResult parseResult_;
+ PointerType invalidSchemaPointer_;
+ const Ch* invalidSchemaKeyword_;
+ PointerType invalidDocumentPointer_;
+};
+
RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__)
RAPIDJSON_DIAG_POP
#endif
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
#endif // RAPIDJSON_SCHEMA_H_
diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp
index e742a12..95b5bb0 100644
--- a/test/unittest/schematest.cpp
+++ b/test/unittest/schematest.cpp
@@ -16,6 +16,11 @@
#include "rapidjson/schema.h"
#include "rapidjson/stringbuffer.h"
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(variadic-macros)
+#endif
+
using namespace rapidjson;
#define TEST_HASHER(json1, json2, expected) \
@@ -95,7 +100,7 @@ TEST(SchemaValidator, Hasher) {
{\
SchemaValidator validator(schema);\
Document d;\
- printf("\n%s\n", json);\
+ /*printf("\n%s\n", json);*/\
d.Parse(json);\
EXPECT_FALSE(d.HasParseError());\
EXPECT_TRUE(expected == d.Accept(validator));\
@@ -115,7 +120,7 @@ TEST(SchemaValidator, Hasher) {
{\
SchemaValidator validator(schema);\
Document d;\
- printf("\n%s\n", json);\
+ /*printf("\n%s\n", json);*/\
d.Parse(json);\
EXPECT_FALSE(d.HasParseError());\
EXPECT_FALSE(d.Accept(validator));\
@@ -841,16 +846,16 @@ TEST(SchemaValidator, AllOf_Nested) {
template
static char* ReadFile(const char* filename, Allocator& allocator) {
const char *paths[] = {
- "%s",
- "bin/%s",
- "../bin/%s",
- "../../bin/%s",
- "../../../bin/%s"
+ "",
+ "bin/",
+ "../bin/",
+ "../../bin/",
+ "../../../bin/"
};
char buffer[1024];
FILE *fp = 0;
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
- sprintf(buffer, paths[i], filename);
+ sprintf(buffer, "%s%s", paths[i], filename);
fp = fopen(buffer, "rb");
if (fp)
break;
@@ -860,9 +865,9 @@ static char* ReadFile(const char* filename, Allocator& allocator) {
return 0;
fseek(fp, 0, SEEK_END);
- size_t length = (size_t)ftell(fp);
+ size_t length = static_cast(ftell(fp));
fseek(fp, 0, SEEK_SET);
- char* json = (char*)allocator.Malloc(length + 1);
+ char* json = reinterpret_cast(allocator.Malloc(length + 1));
size_t readLength = fread(json, 1, length, fp);
json[readLength] = '\0';
fclose(fp);
@@ -1087,4 +1092,39 @@ TEST(SchemaValidator, TestSuite) {
printf("%d / %d passed (%2d%%)\n", passCount, testCount, passCount * 100 / testCount);
// if (passCount != testCount)
// ADD_FAILURE();
-}
\ No newline at end of file
+}
+
+TEST(SchemaValidatingReader, Valid) {
+ Document sd;
+ sd.Parse("{ \"type\": \"string\", \"enum\" : [\"red\", \"amber\", \"green\"] }");
+ SchemaDocument s(sd);
+
+ Document d;
+ StringStream ss("\"red\"");
+ SchemaValidatingReader > reader(ss, s);
+ d.Populate(reader);
+ EXPECT_TRUE(reader.GetParseResult());
+ EXPECT_TRUE(d.IsString());
+ EXPECT_STREQ("red", d.GetString());
+}
+
+TEST(SchemaValidatingReader, Invalid) {
+ Document sd;
+ sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}");
+ SchemaDocument s(sd);
+
+ Document d;
+ StringStream ss("\"ABCD\"");
+ SchemaValidatingReader > reader(ss, s);
+ d.Populate(reader);
+ EXPECT_FALSE(reader.GetParseResult());
+ EXPECT_EQ(kParseErrorTermination, reader.GetParseResult().Code());
+ EXPECT_STREQ("maxLength", reader.GetInvalidSchemaKeyword());
+ EXPECT_TRUE(reader.GetInvalidSchemaPointer() == SchemaDocument::PointerType(""));
+ EXPECT_TRUE(reader.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
+ EXPECT_TRUE(d.IsNull());
+}
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
diff --git a/test/unittest/strfunctest.cpp b/test/unittest/strfunctest.cpp
index 3e1a1ce..186755c 100644
--- a/test/unittest/strfunctest.cpp
+++ b/test/unittest/strfunctest.cpp
@@ -28,4 +28,4 @@ TEST(StrFunc, CountStringCodePoint) {
EXPECT_TRUE(CountStringCodePoint >("\xC2\xA2\xE2\x82\xAC\xF0\x9D\x84\x9E", 9, &count)); // cents euro G-clef
EXPECT_EQ(3u, count);
EXPECT_FALSE(CountStringCodePoint >("\xC2\xA2\xE2\x82\xAC\xF0\x9D\x84\x9E\x80", 10, &count));
-}
\ No newline at end of file
+}