From a38104a165e3a7e4e1fc5647c6a7c19b968259b3 Mon Sep 17 00:00:00 2001 From: shadeware Date: Sun, 19 Mar 2017 03:03:36 +0300 Subject: [PATCH 001/128] fix typos in doc code --- doc/schema.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/schema.md b/doc/schema.md index 8b4195b..29ba4f5 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -20,7 +20,7 @@ Secondly, construct a `SchemaValidator` with the `SchemaDocument`. It is similar // ... Document sd; -if (!sd.Parse(schemaJson).HasParseError()) { +if (sd.Parse(schemaJson).HasParseError()) { // the schema is not a valid JSON. // ... } @@ -28,7 +28,7 @@ SchemaDocument schema(sd); // Compile a Document to SchemaDocument // sd is no longer needed here. Document d; -if (!d.Parse(inputJson).HasParseError()) { +if (d.Parse(inputJson).HasParseError()) { // the input is not a valid JSON. // ... } From 430e8d4c9b6c52e007e57f6f1380c905c1c266df Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 20 Mar 2017 11:20:04 +0800 Subject: [PATCH 002/128] Update schema.zh-cn.md --- doc/schema.zh-cn.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/schema.zh-cn.md b/doc/schema.zh-cn.md index fa076de..5df1f31 100644 --- a/doc/schema.zh-cn.md +++ b/doc/schema.zh-cn.md @@ -20,7 +20,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document // ... Document sd; -if (!sd.Parse(schemaJson).HasParseError()) { +if (sd.Parse(schemaJson).HasParseError()) { // 此 schema 不是合法的 JSON // ... } @@ -28,7 +28,7 @@ SchemaDocument schema(sd); // 把一个 Document 编译至 SchemaDocument // 之后不再需要 sd Document d; -if (!d.Parse(inputJson).HasParseError()) { +if (d.Parse(inputJson).HasParseError()) { // 输入不是一个合法的 JSON // ... } From da4fd6794c8709667137d667525e5005a091adbb Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Date: Wed, 22 Mar 2017 10:19:54 +0000 Subject: [PATCH 003/128] Fixed bug on space hexadecimal encoding --- include/rapidjson/reader.h | 12 ++++++------ include/rapidjson/writer.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 00ab6a5..6ba3f17 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -990,7 +990,7 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -999,7 +999,7 @@ private: const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -1053,7 +1053,7 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -1062,7 +1062,7 @@ private: const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -1101,7 +1101,7 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -1110,7 +1110,7 @@ private: const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index cb7afd5..219da5e 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -585,7 +585,7 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -594,7 +594,7 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped From 3c6e2cf0309c4e146c8ed18fd16096136fecbf00 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Date: Thu, 23 Mar 2017 10:14:17 +0000 Subject: [PATCH 004/128] Added unittests for invalid ascii control chars --- test/unittest/readertest.cpp | 2 ++ test/unittest/writertest.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 3555f11..5078f52 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -725,6 +725,8 @@ TEST(Reader, ParseString_Error) { // Malform ASCII sequence TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x80u), '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x01u), '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(ASCII<>, UTF8<>, char, ARRAY('[', '\"', char(0x1Cu), '\"', ']', '\0')); #undef ARRAY #undef TEST_STRINGARRAY_ERROR diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index e630bb9..bc28e02 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -401,6 +401,16 @@ TEST(Writer, InvalidEncoding) { static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF EXPECT_FALSE(writer.String(s)); } + + // Fail in decoding invalid ASCII control bytes + { + GenericStringBuffer > buffer; + Writer >, UTF8<>, UTF16<> > writer(buffer); + writer.StartArray(); + EXPECT_FALSE(writer.String("\x01")); + EXPECT_FALSE(writer.String("\x1C")); + writer.EndArray(); + } } TEST(Writer, ValidateEncoding) { From 85500e8c8f1eabe10bcf7944e71fbb2dbcc893de Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Date: Fri, 24 Mar 2017 13:37:23 +0000 Subject: [PATCH 005/128] Changed error code for invalid special ascii chars, fixed writer tests --- include/rapidjson/reader.h | 2 +- test/unittest/writertest.cpp | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 6ba3f17..ccc025e 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -955,7 +955,7 @@ private: if (c == '\0') RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); else - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); } else { size_t offset = is.Tell(); diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index bc28e02..b190c6c 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -401,16 +401,6 @@ TEST(Writer, InvalidEncoding) { static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF EXPECT_FALSE(writer.String(s)); } - - // Fail in decoding invalid ASCII control bytes - { - GenericStringBuffer > buffer; - Writer >, UTF8<>, UTF16<> > writer(buffer); - writer.StartArray(); - EXPECT_FALSE(writer.String("\x01")); - EXPECT_FALSE(writer.String("\x1C")); - writer.EndArray(); - } } TEST(Writer, ValidateEncoding) { @@ -422,8 +412,10 @@ TEST(Writer, ValidateEncoding) { EXPECT_TRUE(writer.String("\xC2\xA2")); // Cents sign U+00A2 EXPECT_TRUE(writer.String("\xE2\x82\xAC")); // Euro sign U+20AC EXPECT_TRUE(writer.String("\xF0\x9D\x84\x9E")); // G clef sign U+1D11E + EXPECT_TRUE(writer.String("\x01")); // SOH control U+0001 + EXPECT_TRUE(writer.String("\x1B")); // Escape control U+001B writer.EndArray(); - EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\"]", buffer.GetString()); + EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\",\"\\u0001\",\"\\u001B\"]", buffer.GetString()); } // Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt From d88be8ef1649eca4602348d1aab5c16c36f83d4f Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 27 Mar 2017 14:05:03 +0800 Subject: [PATCH 006/128] Fix #905 unable to set writeFlags for PrettyWriter --- include/rapidjson/prettywriter.h | 2 +- test/unittest/prettywritertest.cpp | 43 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index ef36a8c..98dfb30 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -47,7 +47,7 @@ enum PrettyFormatOptions { template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class PrettyWriter : public Writer { public: - typedef Writer Base; + typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor diff --git a/test/unittest/prettywritertest.cpp b/test/unittest/prettywritertest.cpp index bfc736f..1e1ca1a 100644 --- a/test/unittest/prettywritertest.cpp +++ b/test/unittest/prettywritertest.cpp @@ -258,6 +258,49 @@ TEST(PrettyWriter, InvalidEventSequence) { } } +TEST(PrettyWriter, NaN) { + double nan = std::numeric_limits::quiet_NaN(); + + EXPECT_TRUE(internal::Double(nan).IsNan()); + StringBuffer buffer; + { + PrettyWriter writer(buffer); + EXPECT_FALSE(writer.Double(nan)); + } + { + PrettyWriter, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer); + EXPECT_TRUE(writer.Double(nan)); + EXPECT_STREQ("NaN", buffer.GetString()); + } + GenericStringBuffer > buffer2; + PrettyWriter > > writer2(buffer2); + EXPECT_FALSE(writer2.Double(nan)); +} + +TEST(PrettyWriter, Inf) { + double inf = std::numeric_limits::infinity(); + + EXPECT_TRUE(internal::Double(inf).IsInf()); + StringBuffer buffer; + { + PrettyWriter writer(buffer); + EXPECT_FALSE(writer.Double(inf)); + } + { + PrettyWriter writer(buffer); + EXPECT_FALSE(writer.Double(-inf)); + } + { + PrettyWriter, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer); + EXPECT_TRUE(writer.Double(inf)); + } + { + PrettyWriter, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer); + EXPECT_TRUE(writer.Double(-inf)); + } + EXPECT_STREQ("Infinity-Infinity", buffer.GetString()); +} + TEST(PrettyWriter, Issue_889) { char buf[100] = "Hello"; From 77f643dc511eaa3a1ce0e9dfa2976282ecc6eede Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 7 Apr 2017 10:23:30 +0800 Subject: [PATCH 007/128] Fix #910 incorrect casting --- include/rapidjson/document.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 6de441f..a2b044c 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2293,7 +2293,7 @@ public: template GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - MemoryStream ms(static_cast(str), length * sizeof(typename SourceEncoding::Ch)); + MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); EncodedInputStream is(ms); ParseStream(is); return *this; From ec90588c72ad4192d53b348298b0dd7f790524fa Mon Sep 17 00:00:00 2001 From: Zhihao Yuan Date: Sat, 8 Apr 2017 22:49:13 -0500 Subject: [PATCH 008/128] Fix a non-type template parameter type mismatch This issues a warning in gcc7. --- include/rapidjson/rapidjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index e667d8b..19a3019 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -413,7 +413,7 @@ RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_BEGIN template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; -template struct StaticAssertTest {}; +template struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END #define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) From f93a29bec2316d3b5d7c33cb6977da6690a29be8 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Fri, 14 Apr 2017 20:19:16 +0200 Subject: [PATCH 009/128] RAPIDJSON_STATIC_ASSERT: use C++11 static_assert, if available --- include/rapidjson/rapidjson.h | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index e667d8b..a6281c0 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -49,6 +49,11 @@ // token stringification #define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) #define RAPIDJSON_DO_STRINGIFY(x) #x + +// token concatenation +#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) +#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) +#define RAPIDJSON_DO_JOIN2(X, Y) X##Y //!@endcond /*! \def RAPIDJSON_MAJOR_VERSION @@ -405,7 +410,15 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_STATIC_ASSERT -// Adopt from boost +// Prefer C++11 static_assert, if available +#ifndef RAPIDJSON_STATIC_ASSERT +#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) +#define RAPIDJSON_STATIC_ASSERT(x) \ + static_assert(x, RAPIDJSON_STRINGIFY(x)) +#endif // C++11 +#endif // RAPIDJSON_STATIC_ASSERT + +// Adopt C++03 implementation from boost #ifndef RAPIDJSON_STATIC_ASSERT #ifndef __clang__ //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN @@ -416,10 +429,6 @@ template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; template struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END -#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) -#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) -#define RAPIDJSON_DO_JOIN2(X, Y) X##Y - #if defined(__GNUC__) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else @@ -438,7 +447,7 @@ RAPIDJSON_NAMESPACE_END typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif +#endif // RAPIDJSON_STATIC_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY From 2291258bb8adb87e5da30ed2b12fa9929d0e76f8 Mon Sep 17 00:00:00 2001 From: Alejandro Martinez Date: Tue, 11 Apr 2017 02:02:15 +0000 Subject: [PATCH 010/128] Added ARM-Neon support for SIMD.SkipWhitespace* Change-Id: Iaf210d029758723a7eeb7f28fc10cab7467889a9 Signed-off-by: Jun He --- doc/faq.md | 2 +- doc/faq.zh-cn.md | 2 +- doc/internals.md | 7 +- doc/internals.zh-cn.md | 7 +- include/rapidjson/rapidjson.h | 18 ++- include/rapidjson/reader.h | 264 +++++++++++++++++++++++++++++++- include/rapidjson/writer.h | 72 ++++++++- test/perftest/perftest.h | 3 + test/perftest/rapidjsontest.cpp | 2 + test/unittest/simdtest.cpp | 4 + 10 files changed, 365 insertions(+), 16 deletions(-) diff --git a/doc/faq.md b/doc/faq.md index 1b0541c..4946cfe 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -256,7 +256,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres 3. What is SIMD? How it is applied in RapidJSON? - [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.2 to accelerate whitespace skipping. This improves performance of parsing indent formatted JSON. Define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` macro to enable this feature. However, running the executable on a machine without such instruction set support will make it crash. + [SIMD](http://en.wikipedia.org/wiki/SIMD) instructions can perform parallel computation in modern CPUs. RapidJSON support Intel's SSE2/SSE4.2 and ARM's Neon to accelerate whitespace/tabspace/carriage-return/line-feed skipping. This improves performance of parsing indent formatted JSON. Define `RAPIDJSON_SSE2`, `RAPIDJSON_SSE42` or `RAPIDJSON_NEON` macro to enable this feature. However, running the executable on a machine without such instruction set support will make it crash. 4. Does it consume a lot of memory? diff --git a/doc/faq.zh-cn.md b/doc/faq.zh-cn.md index f12d830..307b02f 100644 --- a/doc/faq.zh-cn.md +++ b/doc/faq.zh-cn.md @@ -257,7 +257,7 @@ 3. 什是是 SIMD?它如何用于 RapidJSON? - [SIMD](http://en.wikipedia.org/wiki/SIMD) 指令可以在现代 CPU 中执行并行运算。RapidJSON 支持了 Intel 的 SSE2/SSE4.2 去加速跳过空白字符。在解析含缩进的 JSON 时,这能提升性能。只要定义名为 `RAPIDJSON_SSE2` 或 `RAPIDJSON_SSE42` 的宏,就能启动这个功能。然而,若在不支持这些指令集的机器上执行这些可执行文件,会导致崩溃。 + [SIMD](http://en.wikipedia.org/wiki/SIMD) 指令可以在现代 CPU 中执行并行运算。RapidJSON 支持使用 Intel 的 SSE2/SSE4.2 和 ARM 的 Neon 来加速对空白符、制表符、回车符和换行符的过滤处理。在解析含缩进的 JSON 时,这能提升性能。只要定义名为 `RAPIDJSON_SSE2` ,`RAPIDJSON_SSE42` 或 `RAPIDJSON_NEON` 的宏,就能启动这个功能。然而,若在不支持这些指令集的机器上执行这些可执行文件,会导致崩溃。 4. 它会消耗许多内存么? diff --git a/doc/internals.md b/doc/internals.md index 49802a0..2fff2d9 100644 --- a/doc/internals.md +++ b/doc/internals.md @@ -183,17 +183,20 @@ void SkipWhitespace(InputStream& s) { However, this requires 4 comparisons and a few branching for each character. This was found to be a hot spot. -To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON only supports SSE2 and SSE4.2 instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing. +To accelerate this process, SIMD was applied to compare 16 characters with 4 white spaces for each iteration. Currently RapidJSON supports SSE2, SSE4.2 and ARM Neon instructions for this. And it is only activated for UTF-8 memory streams, including string stream or *in situ* parsing. -To enable this optimization, need to define `RAPIDJSON_SSE2` or `RAPIDJSON_SSE42` before including `rapidjson.h`. Some compilers can detect the setting, as in `perftest.h`: +To enable this optimization, need to define `RAPIDJSON_SSE2`, `RAPIDJSON_SSE42` or `RAPIDJSON_NEON` before including `rapidjson.h`. Some compilers can detect the setting, as in `perftest.h`: ~~~cpp // __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler. // We use -march=native with gmake to enable -msse2 and -msse4.2, if supported. +// Likewise, __ARM_NEON is used to detect Neon. #if defined(__SSE4_2__) # define RAPIDJSON_SSE42 #elif defined(__SSE2__) # define RAPIDJSON_SSE2 +#elif defined(__ARM_NEON) +# define RAPIDJSON_NEON #endif ~~~ diff --git a/doc/internals.zh-cn.md b/doc/internals.zh-cn.md index ec57959..0c8bc06 100644 --- a/doc/internals.zh-cn.md +++ b/doc/internals.zh-cn.md @@ -183,17 +183,20 @@ void SkipWhitespace(InputStream& s) { 但是,这需要对每个字符进行4次比较以及一些分支。这被发现是一个热点。 -为了加速这一处理,RapidJSON 使用 SIMD 来在一次迭代中比较16个字符和4个空格。目前 RapidJSON 只支持 SSE2 和 SSE4.2 指令。同时它也只会对 UTF-8 内存流启用,包括字符串流或 *原位* 解析。 +为了加速这一处理,RapidJSON 使用 SIMD 来在一次迭代中比较16个字符和4个空格。目前 RapidJSON 支持 SSE2 , SSE4.2 和 ARM Neon 指令。同时它也只会对 UTF-8 内存流启用,包括字符串流或 *原位* 解析。 -你可以通过在包含 `rapidjson.h` 之前定义 `RAPIDJSON_SSE2` 或 `RAPIDJSON_SSE42` 来启用这个优化。一些编译器可以检测这个设置,如 `perftest.h`: +你可以通过在包含 `rapidjson.h` 之前定义 `RAPIDJSON_SSE2` , `RAPIDJSON_SSE42` 或 `RAPIDJSON_NEON` 来启用这个优化。一些编译器可以检测这个设置,如 `perftest.h`: ~~~cpp // __SSE2__ 和 __SSE4_2__ 可被 gcc、clang 和 Intel 编译器识别: // 如果支持的话,我们在 gmake 中使用了 -march=native 来启用 -msse2 和 -msse4.2 +// 同样的, __ARM_NEON 被用于识别Neon #if defined(__SSE4_2__) # define RAPIDJSON_SSE42 #elif defined(__SSE2__) # define RAPIDJSON_SSE2 +#elif defined(__ARM_NEON) +# define RAPIDJSON_NEON #endif ~~~ diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index f41bb20..57ab851 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -325,17 +325,17 @@ #endif /////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD /*! \def RAPIDJSON_SIMD \ingroup RAPIDJSON_CONFIG - \brief Enable SSE2/SSE4.2 optimization. + \brief Enable SSE2/SSE4.2/Neon optimization. RapidJSON supports optimized implementations for some parsing operations - based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible - processors. + based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel + or ARM compatible processors. - To enable these optimizations, two different symbols can be defined; + To enable these optimizations, three different symbols can be defined; \code // Enable SSE2 optimization. #define RAPIDJSON_SSE2 @@ -344,13 +344,17 @@ #define RAPIDJSON_SSE42 \endcode - \c RAPIDJSON_SSE42 takes precedence, if both are defined. + // Enable ARM Neon optimization. + #define RAPIDJSON_NEON + \endcode + + \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. If any of these symbols is defined, RapidJSON defines the macro \c RAPIDJSON_SIMD to indicate the availability of the optimized code. */ #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ - || defined(RAPIDJSON_DOXYGEN_RUNNING) + || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) #define RAPIDJSON_SIMD #endif diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index ccc025e..120c311 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -33,6 +33,8 @@ #include #elif defined(RAPIDJSON_SSE2) #include +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef _MSC_VER @@ -411,7 +413,92 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { return SkipWhitespace(p, end); } -#endif // RAPIDJSON_SSE2 +#elif defined(RAPIDJSON_NEON) + +//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz =__builtin_clzll(high);; + return p + 8 + (lz >> 3); + } + } else { + int lz = __builtin_clzll(low);; + return p + (lz >> 3); + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (; p <= end - 16; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz = __builtin_clzll(high); + return p + 8 + (lz >> 3); + } + } else { + int lz = __builtin_clzll(low); + return p + (lz >> 3); + } + } + + return SkipWhitespace(p, end); +} + +#endif // RAPIDJSON_NEON #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream @@ -1129,7 +1216,180 @@ private: is.src_ = is.dst_ = p; } -#endif +#elif defined(RAPIDJSON_NEON) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high);; + length = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low);; + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + vst1q_u8(reinterpret_cast(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16, q += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high); + length = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low); + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + for (const char* pend = p + length; p != pend; ) { + *q++ = *p++; + } + break; + } + vst1q_u8(reinterpret_cast(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz = __builtin_clzll(high); + p += 8 + (lz >> 3); + break; + } + } else { + int lz = __builtin_clzll(low); + p += lz >> 3; + break; + } + } + + is.src_ = is.dst_ = p; + } +#endif // RAPIDJSON_NEON template class NumberStream; diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 219da5e..61cd070 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -32,6 +32,8 @@ #include #elif defined(RAPIDJSON_SSE2) #include +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef _MSC_VER @@ -619,7 +621,75 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } -#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +#elif defined(RAPIDJSON_NEON) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (; p != endAligned; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType len = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high); + len = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low); + len = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#endif // RAPIDJSON_NEON RAPIDJSON_NAMESPACE_END diff --git a/test/perftest/perftest.h b/test/perftest/perftest.h index b098e41..953f95d 100644 --- a/test/perftest/perftest.h +++ b/test/perftest/perftest.h @@ -24,10 +24,13 @@ // __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler. // We use -march=native with gmake to enable -msse2 and -msse4.2, if supported. +// Likewise, __ARM_NEON is used to detect Neon. #if defined(__SSE4_2__) # define RAPIDJSON_SSE42 #elif defined(__SSE2__) # define RAPIDJSON_SSE2 +#elif defined(__ARM_NEON) +# define RAPIDJSON_NEON #endif #define RAPIDJSON_HAS_STDSTRING 1 diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index f14e702..a11a557 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -28,6 +28,8 @@ #define SIMD_SUFFIX(name) name##_SSE2 #elif defined(RAPIDJSON_SSE42) #define SIMD_SUFFIX(name) name##_SSE42 +#elif defined(RAPIDJSON_NEON) +#define SIMD_SUFFIX(name) name##_NEON #else #define SIMD_SUFFIX(name) name #endif diff --git a/test/unittest/simdtest.cpp b/test/unittest/simdtest.cpp index b01b559..7b58cd0 100644 --- a/test/unittest/simdtest.cpp +++ b/test/unittest/simdtest.cpp @@ -21,6 +21,8 @@ # define RAPIDJSON_SSE42 #elif defined(__SSE2__) # define RAPIDJSON_SSE2 +#elif defined(__ARM_NEON) +# define RAPIDJSON_NEON #endif #define RAPIDJSON_NAMESPACE rapidjson_simd @@ -41,6 +43,8 @@ using namespace rapidjson_simd; #define SIMD_SUFFIX(name) name##_SSE2 #elif defined(RAPIDJSON_SSE42) #define SIMD_SUFFIX(name) name##_SSE42 +#elif defined(RAPIDJSON_NEON) +#define SIMD_SUFFIX(name) name##_NEON #else #define SIMD_SUFFIX(name) name #endif From 63423eb6f8aa2b315d810baf8e96e7f2600745d7 Mon Sep 17 00:00:00 2001 From: Oliver Hahm Date: Fri, 21 Apr 2017 14:49:12 +0200 Subject: [PATCH 011/128] fix return values --- include/rapidjson/document.h | 2 +- include/rapidjson/schema.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index a2b044c..c12820e 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -515,7 +515,7 @@ struct TypeHelper { static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(ValueType& v) { return v.GetObject(); } static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } - static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } }; template diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 3dddd3a..44a94f8 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -1789,7 +1789,7 @@ RAPIDJSON_MULTILINEMACRO_END } virtual void FreeState(void* p) { - return StateAllocator::Free(p); + StateAllocator::Free(p); } private: From 885b5cd2f9b0fe9596d58ee28663cb6267559f67 Mon Sep 17 00:00:00 2001 From: Oliver Hahm Date: Fri, 21 Apr 2017 14:49:30 +0200 Subject: [PATCH 012/128] common notation of empty if/else case --- include/rapidjson/schema.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 44a94f8..348dd37 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -1112,8 +1112,8 @@ private: if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); } - else if (maximum_.IsUint64()) - /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64() + else if (maximum_.IsUint64()) { } + /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() else if (!CheckDoubleMaximum(context, static_cast(i))) return false; } From 4fe02e15f9f59debf169e1d17fdf660e0ad08065 Mon Sep 17 00:00:00 2001 From: Matthew Early Date: Sat, 29 Apr 2017 16:07:23 -0400 Subject: [PATCH 013/128] typo --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 4a1d64d..cd30218 100644 --- a/readme.md +++ b/readme.md @@ -84,7 +84,7 @@ To generate user documentation and run tests please proceed with the steps below 3. Change to `build` directory and run `cmake ..` command to configure your build. Windows users can do the same with cmake-gui application. 4. On Windows, build the solution found in the build directory. On Linux, run `make` from the build directory. -On successfull build you will find compiled test and example binaries in `bin` +On successful build you will find compiled test and example binaries in `bin` directory. The generated documentation will be available in `doc/html` directory of the build tree. To run tests after finished build please run `make test` or `ctest` from your build tree. You can get detailed output using `ctest From fe19b7b6016d446722621fb407738209d1a911e8 Mon Sep 17 00:00:00 2001 From: Harry Wong Date: Thu, 4 May 2017 10:08:48 +0800 Subject: [PATCH 014/128] Supress implicit fallthrough in GCC --- include/rapidjson/internal/regex.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/rapidjson/internal/regex.h b/include/rapidjson/internal/regex.h index 1369ea2..6d110bd 100644 --- a/include/rapidjson/internal/regex.h +++ b/include/rapidjson/internal/regex.h @@ -29,6 +29,7 @@ RAPIDJSON_DIAG_OFF(implicit-fallthrough) #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(implicit-fallthrough) #endif #ifdef _MSC_VER From cba45fe9de6923b858edb0780e257b7257aa4f7b Mon Sep 17 00:00:00 2001 From: Harry Wong Date: Thu, 4 May 2017 10:32:45 +0800 Subject: [PATCH 015/128] Onley apply to GCC 7 --- include/rapidjson/internal/regex.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/rapidjson/internal/regex.h b/include/rapidjson/internal/regex.h index 6d110bd..e1a2faa 100644 --- a/include/rapidjson/internal/regex.h +++ b/include/rapidjson/internal/regex.h @@ -29,8 +29,10 @@ RAPIDJSON_DIAG_OFF(implicit-fallthrough) #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) +#if __GNUC__ >= 7 RAPIDJSON_DIAG_OFF(implicit-fallthrough) #endif +#endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH From 568107e178c700fecc7eb3c0da483b1a95a01ece Mon Sep 17 00:00:00 2001 From: Hartwig Date: Wed, 10 May 2017 22:56:01 +0200 Subject: [PATCH 016/128] Add convenience method Key(std::basic_string const&) to Writer --- include/rapidjson/writer.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 61cd070..e610ebb 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -222,6 +222,13 @@ public: bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif + bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object From b61bbbfe371c51c3ee86103bd1da040bcc5a0779 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 11 May 2017 16:41:26 +0800 Subject: [PATCH 017/128] Fix #947 -Weffc++ warning --- example/lookaheadparser/lookaheadparser.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/example/lookaheadparser/lookaheadparser.cpp b/example/lookaheadparser/lookaheadparser.cpp index 29469ed..f627f4d 100644 --- a/example/lookaheadparser/lookaheadparser.cpp +++ b/example/lookaheadparser/lookaheadparser.cpp @@ -2,6 +2,11 @@ #include "rapidjson/document.h" #include +RAPIDJSON_DIAG_PUSH +#ifdef __GNUC__ +RAPIDJSON_DIAG_OFF(effc++) +#endif + // This example demonstrates JSON token-by-token parsing with an API that is // more direct; you don't need to design your logic around a handler object and // callbacks. Instead, you retrieve values from the JSON stream by calling @@ -341,3 +346,5 @@ int main() { return 0; } + +RAPIDJSON_DIAG_POP From f8eb7bae89fb38f7ffe3dd69e04e95986839b0d0 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 12 May 2017 10:32:06 +0800 Subject: [PATCH 018/128] Remove -Weverything See #930 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6823a8..8b90c87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,7 +87,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -Wno-missing-field-initializers") - set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough -Weverything) + set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough) if (RAPIDJSON_BUILD_CXX11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() From 56b7216efe5014a3936da2fc4d01ad1dc45a2250 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 12 May 2017 10:32:41 +0800 Subject: [PATCH 019/128] Fix #949 about -Werror=conversion --- test/unittest/pointertest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp index dbddbed..eed6fba 100644 --- a/test/unittest/pointertest.cpp +++ b/test/unittest/pointertest.cpp @@ -441,8 +441,8 @@ TEST(Pointer, Stringify) { } // Construct a Pointer with static tokens, no dynamic allocation involved. -#define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } -#define INDEX(i) { #i, sizeof(#i) - 1, i } +#define NAME(s) { s, static_cast(sizeof(s) / sizeof(s[0]) - 1), kPointerInvalidIndex } +#define INDEX(i) { #i, static_cast(sizeof(#i) - 1), i } static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(0) }; // equivalent to "/foo/0" From 0033268c115cbfa224937a76685bfb1e55fdb506 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 12 May 2017 17:30:33 +0800 Subject: [PATCH 020/128] Update tutorial.zh-cn.md typo --- doc/tutorial.zh-cn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorial.zh-cn.md b/doc/tutorial.zh-cn.md index ec1315c..6b2588f 100644 --- a/doc/tutorial.zh-cn.md +++ b/doc/tutorial.zh-cn.md @@ -343,7 +343,7 @@ Value o(kObjectType); ![转移语义不需复制。](diagram/move3.png) -在 C++11 中这称为转移赋值操作(move assignment operator)。由于 RapidJSON 支持 C++03,它在赋值操作采用转移语义,其它修改形函数如 `AddMember()`, `PushBack()` 也采用转移语义。 +在 C++11 中这称为转移赋值操作(move assignment operator)。由于 RapidJSON 支持 C++03,它在赋值操作采用转移语义,其它修改型函数如 `AddMember()`, `PushBack()` 也采用转移语义。 ### 转移语义及临时值 {#TemporaryValues} From 4ef1ff4fbac491676702cf9e4f300d504d56cee9 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Thu, 18 May 2017 19:08:23 +0200 Subject: [PATCH 021/128] GenericValue::CopyFrom: add option to force copying of strings Copying the result of an in-situ parsing into another value/document currently requires that the original buffer - still holding the strings from the parsing, outlives the destination object as well. In order to obtain a "full" copy of a GenericValue, this commit adds an optional flag `copyConstStrings` to `CopyFrom`, which then forces to take a copy of all embedded strings in the source value. This solves the problem discussed in #962. --- include/rapidjson/document.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index c12820e..0d13b60 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -615,10 +615,11 @@ public: \tparam SourceAllocator allocator of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) \see CopyFrom() */ template - GenericValue(const GenericValue& rhs, Allocator& allocator) { + GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { switch (rhs.GetType()) { case kObjectType: { SizeType count = rhs.data_.o.size; @@ -645,7 +646,7 @@ public: } break; case kStringType: - if (rhs.data_.f.flags == kConstStringFlag) { + if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { data_.f.flags = rhs.data_.f.flags; data_ = *reinterpret_cast(&rhs.data_); } @@ -850,12 +851,13 @@ public: \tparam SourceAllocator Allocator type of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator to use for copying + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) */ template - GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); this->~GenericValue(); - new (this) GenericValue(rhs, allocator); + new (this) GenericValue(rhs, allocator, copyConstStrings); return *this; } From 77d2fadfb615687038ffeff9dac5acdfc4d5e327 Mon Sep 17 00:00:00 2001 From: "Tomasz Noczynski (Linux)" Date: Thu, 25 May 2017 13:21:57 +0200 Subject: [PATCH 022/128] If storage class is not specified as first in declaration then Intel C++ Compiler 2017 generates message: message #82: storage class is not first --- include/rapidjson/encodings.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/rapidjson/encodings.h b/include/rapidjson/encodings.h index ed7d44d..0df1c34 100644 --- a/include/rapidjson/encodings.h +++ b/include/rapidjson/encodings.h @@ -620,28 +620,28 @@ struct AutoUTF { #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x template - RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { + static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; (*f[os.GetType()])(os, codepoint); } template - RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; (*f[os.GetType()])(os, codepoint); } template - RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { + static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; return (*f[is.GetType()])(is, codepoint); } template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { typedef bool (*ValidateFunc)(InputStream&, OutputStream&); static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; return (*f[is.GetType()])(is, os); @@ -658,7 +658,7 @@ template struct Transcoder { //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; @@ -667,7 +667,7 @@ struct Transcoder { } template - RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; @@ -677,7 +677,7 @@ struct Transcoder { //! Validate one Unicode codepoint from an encoded stream. template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Transcode(is, os); // Since source/target encoding is different, must transcode. } }; @@ -690,19 +690,19 @@ inline void PutUnsafe(Stream& stream, typename Stream::Ch c); template struct Transcoder { template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template - RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same } }; From 294ad93e30abf27e99c037054e8adb1ce853d6e4 Mon Sep 17 00:00:00 2001 From: "Tomasz Noczynski (Linux)" Date: Thu, 25 May 2017 14:14:16 +0200 Subject: [PATCH 023/128] To avoid Intel C++ Compiler #1879 warnings: warning #1879: unimplemented pragma ignored: #pragma intrinsic(_BitScanReverse64) warning #1879: unimplemented pragma ignored: #pragma intrinsic(_umul128) --- include/rapidjson/internal/diyfp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/internal/diyfp.h b/include/rapidjson/internal/diyfp.h index c9fefdc..29abf80 100644 --- a/include/rapidjson/internal/diyfp.h +++ b/include/rapidjson/internal/diyfp.h @@ -21,7 +21,7 @@ #include "../rapidjson.h" -#if defined(_MSC_VER) && defined(_M_AMD64) +#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include #pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_umul128) From 68c96e987bd0eb67ff399904dee6b7c07042ff18 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Sat, 27 May 2017 10:26:35 +0200 Subject: [PATCH 024/128] Fixup #964 by forwarding copyConstStrings recursively As reported by @Llerd in #962, the `copyConstStrings` parameter has not been forwarded recursively to the constructors of object members and array elements. --- include/rapidjson/document.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 0d13b60..57f0b3c 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -626,8 +626,8 @@ public: Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); const typename GenericValue::Member* rm = rhs.GetMembersPointer(); for (SizeType i = 0; i < count; i++) { - new (&lm[i].name) GenericValue(rm[i].name, allocator); - new (&lm[i].value) GenericValue(rm[i].value, allocator); + new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); + new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); } data_.f.flags = kObjectFlag; data_.o.size = data_.o.capacity = count; @@ -639,7 +639,7 @@ public: GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); const GenericValue* re = rhs.GetElementsPointer(); for (SizeType i = 0; i < count; i++) - new (&le[i]) GenericValue(re[i], allocator); + new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); data_.f.flags = kArrayFlag; data_.a.size = data_.a.capacity = count; SetElementsPointer(le); From df6362d45060d7fde9772d21f23af969d039e920 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 9 Jun 2017 10:16:24 +0800 Subject: [PATCH 025/128] Fix patternProperties & additionalProperties lead to ASSERT Fix #825 --- include/rapidjson/schema.h | 4 +++- test/unittest/schematest.cpp | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 348dd37..dd57edb 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -783,8 +783,10 @@ public: if (patternProperties_) { context.patternPropertiesSchemaCount = 0; for (SizeType i = 0; i < patternPropertyCount_; i++) - if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; + context.valueSchema = typeless_; + } } SizeType index; diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 30b3260..e79fec2 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -1322,6 +1322,13 @@ TEST(SchemaValidator, Issue728_AllOfRef) { VALIDATE(s, "{\"key1\": \"abc\", \"key2\": \"def\"}", true); } +TEST(SchemaValidator, Issue825) { + Document sd; + sd.Parse("{\"type\": \"object\", \"additionalProperties\": false, \"patternProperties\": {\"^i\": { \"type\": \"string\" } } }"); + SchemaDocument s(sd); + VALIDATE(s, "{ \"item\": \"hello\" }", true); +} + #ifdef __clang__ RAPIDJSON_DIAG_POP #endif From 6e81d49b3374c1e8667438056c16ab2f3611c1fd Mon Sep 17 00:00:00 2001 From: kyb Date: Thu, 15 Jun 2017 12:36:20 +0300 Subject: [PATCH 026/128] Fixed #985 : Unittest failed with MinGWx64. And few small improvement were done while looking for mistakes. Problem was because of Windows uses backslashes '\', not Unix '/' --- test/unittest/ostreamwrappertest.cpp | 5 +++-- test/unittest/prettywritertest.cpp | 1 + test/unittest/unittest.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/unittest/ostreamwrappertest.cpp b/test/unittest/ostreamwrappertest.cpp index b1d1cd8..50f8da6 100644 --- a/test/unittest/ostreamwrappertest.cpp +++ b/test/unittest/ostreamwrappertest.cpp @@ -69,14 +69,15 @@ static void TestFileStream() { const char* s = "Hello World!\n"; { - ofstream ofs(filename, ios::out | ios::binary); - BasicOStreamWrapper osw(ofs); + FileStreamType ofs(filename, ios::out | ios::binary); + BasicOStreamWrapper osw(ofs); for (const char* p = s; *p; p++) osw.Put(*p); osw.Flush(); } fp = fopen(filename, "r"); + ASSERT_TRUE( fp != NULL ); for (const char* p = s; *p; p++) EXPECT_EQ(*p, static_cast(fgetc(fp))); fclose(fp); diff --git a/test/unittest/prettywritertest.cpp b/test/unittest/prettywritertest.cpp index 1e1ca1a..43617a2 100644 --- a/test/unittest/prettywritertest.cpp +++ b/test/unittest/prettywritertest.cpp @@ -167,6 +167,7 @@ TEST(PrettyWriter, OStreamWrapper) { TEST(PrettyWriter, FileWriteStream) { char filename[L_tmpnam]; FILE* fp = TempFile(filename); + ASSERT_TRUE(fp!=NULL); char buffer[16]; FileWriteStream os(fp, buffer, sizeof(buffer)); PrettyWriter writer(os); diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index e125bf8..5837345 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -78,7 +78,7 @@ inline Ch* StrDup(const Ch* str) { } inline FILE* TempFile(char *filename) { -#ifdef _MSC_VER +#if defined(__WIN32__) || defined(_MSC_VER) filename = tmpnam(filename); // For Visual Studio, tmpnam() adds a backslash in front. Remove it. From a31a380cb81c2f20baf4cd7204815e235ea8d2bd Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Wed, 21 Jun 2017 14:25:47 +0800 Subject: [PATCH 027/128] Improve readme.md Add alt text for images Use https whenever possible Update URLs Use tools.ietf.org for RFC7159 Correct indent for sublists Trim trailing whitespaces --- readme.md | 50 ++++++++++++++++++++++++------------------------- readme.zh-cn.md | 50 ++++++++++++++++++++++++------------------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/readme.md b/readme.md index cd30218..2937619 100644 --- a/readme.md +++ b/readme.md @@ -1,8 +1,8 @@ -![](doc/logo/rapidjson.png) +![RapidJSON logo](doc/logo/rapidjson.png) -![](https://img.shields.io/badge/release-v1.1.0-blue.png) +![Release version](https://img.shields.io/badge/release-v1.1.0-blue.svg) -## A fast JSON parser/generator for C++ with both SAX/DOM style API +## A fast JSON parser/generator for C++ with both SAX/DOM style API Tencent is pleased to support the open source community by making RapidJSON available. @@ -20,12 +20,12 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights | :---------------: | :-----------------: | :-------------------: | | ![lin-badge] | ![win-badge] | ![cov-badge] | -[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status" +[lin-badge]: https://travis-ci.org/miloyip/rapidjson.svg?branch=master "Travis build status" [lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status" -[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/github/miloyip/rapidjson?branch=master&svg=true "AppVeyor build status" [win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status" -[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master -[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master +[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.svg?branch=master "Coveralls coverage" +[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master "Coveralls coverage" ## Introduction @@ -45,8 +45,8 @@ More features can be read [here](doc/features.md). JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at * [Introducing JSON](http://json.org/) -* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt) -* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm) +* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159) +* [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm) ## Highlights in v1.1 (2016-8-25) @@ -74,8 +74,8 @@ RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder RapidJSON uses following software as its dependencies: * [CMake](https://cmake.org/) as a general build tool -* (optional)[Doxygen](http://www.doxygen.org) to build documentation -* (optional)[googletest](https://github.com/google/googletest) for unit and performance testing +* (optional) [Doxygen](http://www.doxygen.org) to build documentation +* (optional) [googletest](https://github.com/google/googletest) for unit and performance testing To generate user documentation and run tests please proceed with the steps below: @@ -139,22 +139,22 @@ The following diagram shows the process. More [examples](https://github.com/miloyip/rapidjson/tree/master/example) are available: * DOM API - * [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API. + * [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API. * SAX API - * [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`. - * [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed. - * [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`. - * [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON. - * [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API. - * [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API. - * [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format. + * [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`. + * [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed. + * [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`. + * [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON. + * [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API. + * [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API. + * [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format. * Schema - * [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema. - + * [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema. + * Advanced - * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings. - * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread. - * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key. - * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`. + * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings. + * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread. + * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key. + * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`. diff --git a/readme.zh-cn.md b/readme.zh-cn.md index b62b2e1..81b84bb 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -1,6 +1,6 @@ -![](doc/logo/rapidjson.png) +![RapidJSON logo](doc/logo/rapidjson.png) -![](https://img.shields.io/badge/release-v1.1.0-blue.png) +![Release version](https://img.shields.io/badge/release-v1.1.0-blue.svg) ## 高效的 C++ JSON 解析/生成器,提供 SAX 及 DOM 风格 API @@ -20,12 +20,12 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights | :---------------: | :-----------------: | :-------------------: | | ![lin-badge] | ![win-badge] | ![cov-badge] | -[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status" +[lin-badge]: https://travis-ci.org/miloyip/rapidjson.svg?branch=master "Travis build status" [lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status" -[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/github/miloyip/rapidjson?branch=master&svg=true "AppVeyor build status" [win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status" -[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master -[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master +[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.svg?branch=master "Coveralls coverage" +[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master "Coveralls coverage" ## 简介 @@ -45,8 +45,8 @@ RapidJSON 是一个 C++ 的 JSON 解析器及生成器。它的灵感来自 [Rap JSON(JavaScript Object Notation)是一个轻量的数据交换格式。RapidJSON 应该完全遵从 RFC7159/ECMA-404,并支持可选的放宽语法。 关于 JSON 的更多信息可参考: * [Introducing JSON](http://json.org/) -* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt) -* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm) +* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159) +* [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm) ## v1.1 中的亮点 (2016-8-25) @@ -73,9 +73,9 @@ RapidJSON 是跨平台的。以下是一些曾测试的平台/编译器组合 RapidJSON 是只有头文件的 C++ 库。只需把 `include/rapidjson` 目录复制至系统或项目的 include 目录中。 RapidJSON 依赖于以下软件: -* [CMake](http://www.cmake.org) 作为通用生成工具 -* (optional)[Doxygen](http://www.doxygen.org) 用于生成文档 -* (optional)[googletest](https://code.google.com/p/googletest/) 用于单元及性能测试 +* [CMake](https://cmake.org/) 作为通用生成工具 +* (optional) [Doxygen](http://www.doxygen.org) 用于生成文档 +* (optional) [googletest](https://github.com/google/googletest) 用于单元及性能测试 生成测试及例子的步骤: @@ -131,22 +131,22 @@ int main() { 还有许多 [例子](https://github.com/miloyip/rapidjson/tree/master/example) 可供参考: * DOM API - * [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): DOM API 的基本使用方法。 + * [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): DOM API 的基本使用方法。 * SAX API - * [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): 使用 `Reader` 解析 JSON 时,打印所有 SAX 事件。 - * [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): 移除 JSON 中所有空白符的命令行工具。 - * [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): 为 JSON 加入缩进与换行的命令行工具,当中使用了 `PrettyWriter`。 - * [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): 把 JSON 中所有字符串改为大写的命令行工具。 - * [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): 使用 SAX API 去解析一个 JSON 报文。 - * [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): 使用 SAX API 去序列化 C++ 对象,生成 JSON。 - * [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): 实现了一个 `JsonxWriter`,它能把 SAX 事件写成 [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html)(一种 XML)格式。这个例子是把 JSON 输入转换成 JSONx 格式的命令行工具。 + * [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): 使用 `Reader` 解析 JSON 时,打印所有 SAX 事件。 + * [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): 移除 JSON 中所有空白符的命令行工具。 + * [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): 为 JSON 加入缩进与换行的命令行工具,当中使用了 `PrettyWriter`。 + * [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): 把 JSON 中所有字符串改为大写的命令行工具。 + * [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): 使用 SAX API 去解析一个 JSON 报文。 + * [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): 使用 SAX API 去序列化 C++ 对象,生成 JSON。 + * [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): 实现了一个 `JsonxWriter`,它能把 SAX 事件写成 [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html)(一种 XML)格式。这个例子是把 JSON 输入转换成 JSONx 格式的命令行工具。 * Schema API - * [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp): 使用 JSON Schema 去校验 JSON 的命令行工具。 - + * [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp): 使用 JSON Schema 去校验 JSON 的命令行工具。 + * 进阶 - * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,可自动处理任何 UTF 编码的 JSON。 - * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例子中的 `AsyncDocumentParser` 类使用 C++ 线程来逐段解析 JSON。 - * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 移取使用者指定的键值的命令行工具。 - * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生成器(generator)去填充一个 `Document`。 \ No newline at end of file + * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,可自动处理任何 UTF 编码的 JSON。 + * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例子中的 `AsyncDocumentParser` 类使用 C++ 线程来逐段解析 JSON。 + * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 移取使用者指定的键值的命令行工具。 + * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生成器(generator)去填充一个 `Document`。 \ No newline at end of file From 0d62f5cd359be662a5b378b8a04862a9bce645f5 Mon Sep 17 00:00:00 2001 From: Leo Mehr Date: Thu, 29 Jun 2017 20:09:13 -0400 Subject: [PATCH 028/128] Tutorial: fix typos in examples and broken links In the move example, the code uses `contacts` when the diagrams use `contact` (no 's') The code in the example: ``` Value contacts(kArrayType); // adding elements to contacts array. // ... o.AddMember("contacts", contacts, d.GetAllocator()); // deep clone contacts (may be with lots of allocations) // destruct contacts. ``` --- doc/diagram/move2.dot | 8 ++++---- doc/diagram/move3.dot | 8 ++++---- doc/tutorial.md | 22 +++++++++++----------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/doc/diagram/move2.dot b/doc/diagram/move2.dot index 7037ea6..2319871 100644 --- a/doc/diagram/move2.dot +++ b/doc/diagram/move2.dot @@ -18,7 +18,7 @@ digraph { node [shape=Mrecord, style=filled, colorscheme=spectral7] - c1 [label="{contact:array|}", fillcolor=4] + c1 [label="{contacts:array|}", fillcolor=4] c11 [label="{|}"] c12 [label="{|}"] c13 [shape="none", label="...", style="solid"] @@ -41,13 +41,13 @@ digraph { node [shape=Mrecord, style=filled, colorscheme=spectral7] - c2 [label="{contact:array|}", fillcolor=4] + c2 [label="{contacts:array|}", fillcolor=4] c3 [label="{array|}", fillcolor=4] c21 [label="{|}"] c22 [label="{|}"] c23 [shape=none, label="...", style="solid"] o2 [label="{o:object|}", fillcolor=3] - cs [label="{string|\"contact\"}", fillcolor=5] + cs [label="{string|\"contacts\"}", fillcolor=5] c31 [label="{|}"] c32 [label="{|}"] c33 [shape="none", label="...", style="solid"] @@ -59,4 +59,4 @@ digraph { c3 -> { c31; c32; c33 } } ghost -> o2 [style=invis] -} \ No newline at end of file +} diff --git a/doc/diagram/move3.dot b/doc/diagram/move3.dot index c197b99..57adb4f 100644 --- a/doc/diagram/move3.dot +++ b/doc/diagram/move3.dot @@ -19,7 +19,7 @@ digraph { node [shape=Mrecord, style=filled, colorscheme=spectral7] - c1 [label="{contact:array|}", fillcolor=4] + c1 [label="{contacts:array|}", fillcolor=4] c11 [label="{|}"] c12 [label="{|}"] c13 [shape=none, label="...", style="solid"] @@ -42,13 +42,13 @@ digraph { node [shape=Mrecord, style=filled, colorscheme=spectral7] - c2 [label="{contact:null|}", fillcolor=1] + c2 [label="{contacts:null|}", fillcolor=1] c3 [label="{array|}", fillcolor=4] c21 [label="{|}"] c22 [label="{|}"] c23 [shape="none", label="...", style="solid"] o2 [label="{o:object|}", fillcolor=3] - cs [label="{string|\"contact\"}", fillcolor=5] + cs [label="{string|\"contacts\"}", fillcolor=5] c2 -> o2 [style="dashed", constraint=false, label="AddMember", style=invis] edge [arrowhead=vee] @@ -57,4 +57,4 @@ digraph { cs -> c3 [arrowhead=none] } ghost -> o2 [style=invis] -} \ No newline at end of file +} diff --git a/doc/tutorial.md b/doc/tutorial.md index cb76b4b..4a06a83 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -2,7 +2,7 @@ This tutorial introduces the basics of the Document Object Model(DOM) API. -As shown in [Usage at a glance](@ref index), a JSON can be parsed into DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON. +As shown in [Usage at a glance](../readme.md#usage-at-a-glance), a JSON can be parsed into DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON. [TOC] @@ -55,7 +55,7 @@ printf("hello = %s\n", document["hello"].GetString()); ~~~~~~~~~~ ~~~~~~~~~~ -world +hello = world ~~~~~~~~~~ JSON true/false values are represented as `bool`. @@ -65,7 +65,7 @@ printf("t = %s\n", document["t"].GetBool() ? "true" : "false"); ~~~~~~~~~~ ~~~~~~~~~~ -true +t = true ~~~~~~~~~~ JSON null can be queryed by `IsNull()`. @@ -74,7 +74,7 @@ printf("n = %s\n", document["n"].IsNull() ? "null" : "?"); ~~~~~~~~~~ ~~~~~~~~~~ -null +n = null ~~~~~~~~~~ JSON number type represents all numeric values. However, C++ needs more specific type for manipulation. @@ -526,11 +526,11 @@ Swapping two DOM trees is fast (constant time), despite the complexity of the tr This tutorial shows the basics of DOM tree query and manipulation. There are several important concepts in RapidJSON: -1. [Streams](doc/stream.md) are channels for reading/writing JSON, which can be a in-memory string, or file stream, etc. User can also create their streams. -2. [Encoding](doc/encoding.md) defines which character encoding is used in streams and memory. RapidJSON also provide Unicode conversion/validation internally. -3. [DOM](doc/dom.md)'s basics are already covered in this tutorial. Uncover more advanced features such as *in situ* parsing, other parsing options and advanced usages. -4. [SAX](doc/sax.md) is the foundation of parsing/generating facility in RapidJSON. Learn how to use `Reader`/`Writer` to implement even faster applications. Also try `PrettyWriter` to format the JSON. -5. [Performance](doc/performance.md) shows some in-house and third-party benchmarks. -6. [Internals](doc/internals.md) describes some internal designs and techniques of RapidJSON. +1. [Streams](stream.md) are channels for reading/writing JSON, which can be a in-memory string, or file stream, etc. User can also create their streams. +2. [Encoding](encoding.md) defines which character encoding is used in streams and memory. RapidJSON also provide Unicode conversion/validation internally. +3. [DOM](dom.md)'s basics are already covered in this tutorial. Uncover more advanced features such as *in situ* parsing, other parsing options and advanced usages. +4. [SAX](sax.md) is the foundation of parsing/generating facility in RapidJSON. Learn how to use `Reader`/`Writer` to implement even faster applications. Also try `PrettyWriter` to format the JSON. +5. [Performance](performance.md) shows some in-house and third-party benchmarks. +6. [Internals](internals.md) describes some internal designs and techniques of RapidJSON. -You may also refer to the [FAQ](doc/faq.md), API documentation, examples and unit tests. +You may also refer to the [FAQ](faq.md), API documentation, examples and unit tests. From 3aafe12c91068f5403ec737ea9766eccabf17302 Mon Sep 17 00:00:00 2001 From: Leo Mehr Date: Fri, 30 Jun 2017 12:42:06 -0400 Subject: [PATCH 029/128] undo changes to links and some minor changes to make the readme more easily readable --- doc/tutorial.md | 64 ++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/doc/tutorial.md b/doc/tutorial.md index 4a06a83..167b81d 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -2,7 +2,7 @@ This tutorial introduces the basics of the Document Object Model(DOM) API. -As shown in [Usage at a glance](../readme.md#usage-at-a-glance), a JSON can be parsed into DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON. +As shown in [Usage at a glance](@ref index), JSON can be parsed into a DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON. [TOC] @@ -14,7 +14,7 @@ Each JSON value is stored in a type called `Value`. A `Document`, representing t In this section, we will use excerpt of `example/tutorial/tutorial.cpp`. -Assumes we have a JSON stored in a C string (`const char* json`): +Assume we have the following JSON stored in a C string (`const char* json`): ~~~~~~~~~~js { "hello": "world", @@ -68,7 +68,7 @@ printf("t = %s\n", document["t"].GetBool() ? "true" : "false"); t = true ~~~~~~~~~~ -JSON null can be queryed by `IsNull()`. +JSON null can be queryed with `IsNull()`. ~~~~~~~~~~cpp printf("n = %s\n", document["n"].IsNull() ? "null" : "?"); ~~~~~~~~~~ @@ -115,15 +115,15 @@ a[3] = 4 Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call `GetInt()`, for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined. -In the following, details about querying individual types are discussed. +In the following sections we discuss details about querying individual types. ## Query Array {#QueryArray} -By default, `SizeType` is typedef of `unsigned`. In most systems, array is limited to store up to 2^32-1 elements. +By default, `SizeType` is typedef of `unsigned`. In most systems, an array is limited to store up to 2^32-1 elements. -You may access the elements in array by integer literal, for example, `a[0]`, `a[1]`, `a[2]`. +You may access the elements in an array by integer literal, for example, `a[0]`, `a[1]`, `a[2]`. -Array is similar to `std::vector`, instead of using indices, you may also use iterator to access all the elements. +Array is similar to `std::vector`: instead of using indices, you may also use iterator to access all the elements. ~~~~~~~~~~cpp for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) printf("%d ", itr->GetInt()); @@ -144,7 +144,7 @@ for (auto& v : a.GetArray()) ## Query Object {#QueryObject} -Similar to array, we can access all object members by iterator: +Similar to Array, we can access all object members by iterator: ~~~~~~~~~~cpp static const char* kTypeNames[] = @@ -190,11 +190,11 @@ for (auto& m : document.GetObject()) ## Querying Number {#QueryNumber} -JSON provide a single numerical type called Number. Number can be integer or real numbers. RFC 4627 says the range of Number is specified by parser. +JSON provides a single numerical type called Number. Number can be an integer or a real number. RFC 4627 says the range of Number is specified by the parser implementation. -As C++ provides several integer and floating point number types, the DOM tries to handle these with widest possible range and good performance. +As C++ provides several integer and floating point number types, the DOM tries to handle these with the widest possible range and good performance. -When a Number is parsed, it is stored in the DOM as either one of the following type: +When a Number is parsed, it is stored in the DOM as one of the following types: Type | Description -----------|--------------------------------------- @@ -204,7 +204,7 @@ Type | Description `int64_t` | 64-bit signed integer `double` | 64-bit double precision floating point -When querying a number, you can check whether the number can be obtained as target type: +When querying a number, you can check whether the number can be obtained as the target type: Checking | Obtaining ------------------|--------------------- @@ -215,9 +215,9 @@ Checking | Obtaining `bool IsInt64()` | `int64_t GetInt64()` `bool IsDouble()` | `double GetDouble()` -Note that, an integer value may be obtained in various ways without conversion. For example, A value `x` containing 123 will make `x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true`. But a value `y` containing -3000000000 will only makes `x.IsInt64() == true`. +Note that, an integer value may be obtained in various ways without conversion. For example, A value `x` containing 123 will make `x.IsInt() == x.IsUint() == x.IsInt64() == x.IsUint64() == true`. But a value `y` containing -3000000000 will only make `x.IsInt64() == true`. -When obtaining the numeric values, `GetDouble()` will convert internal integer representation to a `double`. Note that, `int` and `unsigned` can be safely convert to `double`, but `int64_t` and `uint64_t` may lose precision (since mantissa of `double` is only 52-bits). +When obtaining the numeric values, `GetDouble()` will convert internal integer representation to a `double`. Note that, `int` and `unsigned` can be safely converted to `double`, but `int64_t` and `uint64_t` may lose precision (since mantissa of `double` is only 52-bits). ## Query String {#QueryString} @@ -225,7 +225,7 @@ In addition to `GetString()`, the `Value` class also contains `GetStringLength() According to RFC 4627, JSON strings can contain Unicode character `U+0000`, which must be escaped as `"\u0000"`. The problem is that, C/C++ often uses null-terminated string, which treats ``\0'` as the terminator symbol. -To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need to handle this, you can use `GetStringLength()` API to obtain the correct length of string. +To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need to handle this, you can use `GetStringLength()` to obtain the correct string length. For example, after parsing a the following JSON to `Document d`: @@ -360,14 +360,14 @@ a.PushBack(Value(42).Move(), allocator); // same as above ~~~~~~~~~~ ## Create String {#CreateString} -RapidJSON provide two strategies for storing string. +RapidJSON provides two strategies for storing string. 1. copy-string: allocates a buffer, and then copy the source data into it. 2. const-string: simply store a pointer of string. -Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing string literal, and in-situ parsing which we will mentioned in Document section. +Copy-string is always safe because it owns a copy of the data. Const-string can be used for storing a string literal, and for in-situ parsing which will be mentioned in the DOM section. -To make memory allocation customizable, RapidJSON requires user to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing a allocator (or Document) pointer per Value. +To make memory allocation customizable, RapidJSON requires users to pass an instance of allocator, whenever an operation may require allocation. This design is needed to prevent storing a allocator (or Document) pointer per Value. Therefore, when we assign a copy-string, we call this overloaded `SetString()` with allocator: @@ -385,7 +385,7 @@ In this example, we get the allocator from a `Document` instance. This is a comm Besides, the above `SetString()` requires length. This can handle null characters within a string. There is another `SetString()` overloaded function without the length parameter. And it assumes the input is null-terminated and calls a `strlen()`-like function to obtain the length. -Finally, for string literal or string with safe life-cycle can use const-string version of `SetString()`, which lacks allocator parameter. For string literals (or constant character arrays), simply passing the literal as parameter is safe and efficient: +Finally, for a string literal or string with a safe life-cycle one can use the const-string version of `SetString()`, which lacks an allocator parameter. For string literals (or constant character arrays), simply passing the literal as parameter is safe and efficient: ~~~~~~~~~~cpp Value s; @@ -393,7 +393,7 @@ s.SetString("rapidjson"); // can contain null character, length derived at co s = "rapidjson"; // shortcut, same as above ~~~~~~~~~~ -For character pointer, the RapidJSON requires to mark it as safe before using it without copying. This can be achieved by using the `StringRef` function: +For a character pointer, RapidJSON requires it to be marked as safe before using it without copying. This can be achieved by using the `StringRef` function: ~~~~~~~~~cpp const char * cstr = getenv("USER"); @@ -408,7 +408,7 @@ s = StringRef(cstr,cstr_len); // shortcut, same as above ~~~~~~~~~ ## Modify Array {#ModifyArray} -Value with array type provides similar APIs as `std::vector`. +Value with array type provides an API similar to `std::vector`. * `Clear()` * `Reserve(SizeType, Allocator&)` @@ -418,7 +418,7 @@ Value with array type provides similar APIs as `std::vector`. * `ValueIterator Erase(ConstValueIterator pos)` * `ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)` -Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore require an allocator. +Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore requiring an allocator. Here is an example of `PushBack()`: @@ -433,7 +433,7 @@ for (int i = 5; i <= 10; i++) a.PushBack("Lua", allocator).PushBack("Mio", allocator); ~~~~~~~~~~ -Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. This is called _fluent interface_. +This API differs from STL in that `PushBack()`/`PopBack()` return the array reference itself. This is called _fluent interface_. If you want to add a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)) to the array, you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place: @@ -448,7 +448,7 @@ contact.PushBack(val, document.GetAllocator()); ~~~~~~~~~~ ## Modify Object {#ModifyObject} -Object is a collection of key-value pairs (members). Each key must be a string value. To modify an object, either add or remove members. THe following APIs are for adding members: +The Object class is a collection of key-value pairs (members). Each key must be a string value. To modify an object, either add or remove members. The following API is for adding members: * `Value& AddMember(Value&, Value&, Allocator& allocator)` * `Value& AddMember(StringRefType, Value&, Allocator&)` @@ -462,7 +462,7 @@ contact.AddMember("name", "Milo", document.GetAllocator()); contact.AddMember("married", true, document.GetAllocator()); ~~~~~~~~~~ -The name parameter with `StringRefType` is similar to the interface of `SetString` function for string values. These overloads are used to avoid the need for copying the `name` string, as constant key names are very common in JSON objects. +The name parameter with `StringRefType` is similar to the interface of the `SetString` function for string values. These overloads are used to avoid the need for copying the `name` string, since constant key names are very common in JSON objects. If you need to create a name from a non-constant string or a string without sufficient lifetime (see [Create String](#CreateString)), you need to create a string Value by using the copy-string API. To avoid the need for an intermediate variable, you can use a [temporary value](#TemporaryValues) in place: @@ -526,11 +526,11 @@ Swapping two DOM trees is fast (constant time), despite the complexity of the tr This tutorial shows the basics of DOM tree query and manipulation. There are several important concepts in RapidJSON: -1. [Streams](stream.md) are channels for reading/writing JSON, which can be a in-memory string, or file stream, etc. User can also create their streams. -2. [Encoding](encoding.md) defines which character encoding is used in streams and memory. RapidJSON also provide Unicode conversion/validation internally. -3. [DOM](dom.md)'s basics are already covered in this tutorial. Uncover more advanced features such as *in situ* parsing, other parsing options and advanced usages. -4. [SAX](sax.md) is the foundation of parsing/generating facility in RapidJSON. Learn how to use `Reader`/`Writer` to implement even faster applications. Also try `PrettyWriter` to format the JSON. -5. [Performance](performance.md) shows some in-house and third-party benchmarks. -6. [Internals](internals.md) describes some internal designs and techniques of RapidJSON. +1. [Streams](doc/stream.md) are channels for reading/writing JSON, which can be a in-memory string, or file stream, etc. User can also create their streams. +2. [Encoding](doc/encoding.md) defines which character encoding is used in streams and memory. RapidJSON also provide Unicode conversion/validation internally. +3. [DOM](doc/dom.md)'s basics are already covered in this tutorial. Uncover more advanced features such as *in situ* parsing, other parsing options and advanced usages. +4. [SAX](doc/sax.md) is the foundation of parsing/generating facility in RapidJSON. Learn how to use `Reader`/`Writer` to implement even faster applications. Also try `PrettyWriter` to format the JSON. +5. [Performance](doc/performance.md) shows some in-house and third-party benchmarks. +6. [Internals](doc/internals.md) describes some internal designs and techniques of RapidJSON. -You may also refer to the [FAQ](faq.md), API documentation, examples and unit tests. +You may also refer to the [FAQ](doc/faq.md), API documentation, examples and unit tests. From 14218aeb0a6491130622672495bf5fe7a20ef28a Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Sun, 9 Jul 2017 11:13:31 +0200 Subject: [PATCH 030/128] ParseResult: improve bool conversion and add operator!= * Use safe-bool idiom for boolean conversion to avoid accidental misuse of ParseResult values (closes #989) * Add operator!= to support more comparison expressions (previously silently/erroneously used operator bool) --- include/rapidjson/error/error.h | 10 ++++++++-- test/unittest/documenttest.cpp | 15 ++++++++++++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index 95cb31a..9311d2f 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -104,6 +104,8 @@ enum ParseErrorCode { \see GenericReader::Parse, GenericDocument::Parse */ struct ParseResult { + //!! Unspecified boolean type + typedef bool (ParseResult::*BooleanType)() const; public: //! Default constructor, no error. ParseResult() : code_(kParseErrorNone), offset_(0) {} @@ -115,8 +117,8 @@ public: //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } - //! Conversion to \c bool, returns \c true, iff !\ref IsError(). - operator bool() const { return !IsError(); } + //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). + operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } //! Whether the result is an error. bool IsError() const { return code_ != kParseErrorNone; } @@ -124,6 +126,10 @@ public: bool operator==(ParseErrorCode code) const { return code_ == code; } friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + bool operator!=(const ParseResult& that) const { return !(*this == that); } + bool operator!=(ParseErrorCode code) const { return !(*this == code); } + friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } + //! Reset error code. void Clear() { Set(kParseErrorNone); } //! Update error code and offset. diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index ecd4b79..0ca5801 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -128,8 +128,14 @@ TEST(Document, UnchangedOnParseError) { Document doc; doc.SetArray().PushBack(0, doc.GetAllocator()); + ParseResult noError; + EXPECT_TRUE(noError); + ParseResult err = doc.Parse("{]"); EXPECT_TRUE(doc.HasParseError()); + EXPECT_NE(err, noError); + EXPECT_NE(err.Code(), noError); + EXPECT_NE(noError, doc.GetParseError()); EXPECT_EQ(err.Code(), doc.GetParseError()); EXPECT_EQ(err.Offset(), doc.GetErrorOffset()); EXPECT_TRUE(doc.IsArray()); @@ -138,6 +144,9 @@ TEST(Document, UnchangedOnParseError) { err = doc.Parse("{}"); EXPECT_FALSE(doc.HasParseError()); EXPECT_FALSE(err.IsError()); + EXPECT_TRUE(err); + EXPECT_EQ(err, noError); + EXPECT_EQ(err.Code(), noError); EXPECT_EQ(err.Code(), doc.GetParseError()); EXPECT_EQ(err.Offset(), doc.GetErrorOffset()); EXPECT_TRUE(doc.IsObject()); @@ -488,15 +497,19 @@ TYPED_TEST(DocumentMove, MoveConstructorParseError) { a.Parse("{ 4 = 4]"); ParseResult error(a.GetParseError(), a.GetErrorOffset()); EXPECT_TRUE(a.HasParseError()); + EXPECT_NE(error, noError); + EXPECT_NE(error.Code(), noError); EXPECT_NE(error.Code(), noError.Code()); EXPECT_NE(error.Offset(), noError.Offset()); D b(std::move(a)); EXPECT_FALSE(a.HasParseError()); EXPECT_TRUE(b.HasParseError()); + EXPECT_EQ(a.GetParseError(), noError); EXPECT_EQ(a.GetParseError(), noError.Code()); - EXPECT_EQ(b.GetParseError(), error.Code()); EXPECT_EQ(a.GetErrorOffset(), noError.Offset()); + EXPECT_EQ(b.GetParseError(), error); + EXPECT_EQ(b.GetParseError(), error.Code()); EXPECT_EQ(b.GetErrorOffset(), error.Offset()); D c(std::move(b)); From eefb618ec947837735d08fe81fb94afdd09948d7 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Sun, 9 Jul 2017 11:40:56 +0200 Subject: [PATCH 031/128] Travis: Switch to Ubuntu 14.04 (Trusty) --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f9319f2..38f3a98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ sudo: required -dist: precise +dist: trusty +group: edge language: cpp cache: From f1ba61c7ba5989373880f14f80d2b56f8593eb81 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Sun, 9 Jul 2017 14:31:29 +0200 Subject: [PATCH 032/128] unittest.h: change RAPIDJSON_ASSERT to allow usage in expressions --- test/unittest/unittest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index 5837345..aa091aa 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -117,7 +117,7 @@ public: #pragma GCC diagnostic pop #endif -#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x)) +#define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u) class Random { public: From 47c3c1ec9f5c3724c5befb42f8323e760acc1f69 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Sun, 9 Jul 2017 14:46:59 +0200 Subject: [PATCH 033/128] Improved handling of NULL strings * Safely assert upon passing NULL string without length (requires usage of RAPIDJSON_ASSERT within an expression) * Allow using a NULL string together with an explicit length 0 (GenericStringRef, GenericValue::SetString, ...), see #817 * Add GenericValue::SetString(StringRefType, Allocator&) overload * Add tests for the various cases --- include/rapidjson/document.h | 26 +++++++++++++++++----- test/unittest/valuetest.cpp | 43 +++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 57f0b3c..06451ad 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -308,7 +308,7 @@ struct GenericStringRef { */ #endif explicit GenericStringRef(const CharType* str) - : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); } + : s(str), length(((RAPIDJSON_ASSERT(str != 0)), internal::StrLen(str))) {} //! Create constant string reference from pointer and length #ifndef __clang__ // -Wdocumentation @@ -320,7 +320,7 @@ struct GenericStringRef { */ #endif GenericStringRef(const CharType* str, SizeType len) - : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); } + : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} @@ -331,6 +331,9 @@ struct GenericStringRef { const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: + /// Empty string - used when passing in a NULL pointer + static const Ch emptyString[]; + //! Disallow construction from non-const array template GenericStringRef(CharType (&str)[N]) /* = delete */; @@ -338,6 +341,9 @@ private: GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; }; +template +const CharType GenericStringRef::emptyString[] = { CharType() }; + //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a @@ -352,7 +358,7 @@ private: */ template inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str, internal::StrLen(str)); + return GenericStringRef(str); } //! Mark a character pointer as constant string @@ -1762,7 +1768,7 @@ public: \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ - GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } //! Set this value as a string by copying from source string. /*! \param s source string. @@ -1770,7 +1776,15 @@ public: \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ - GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } + + //! Set this value as a string by copying from source string. + /*! \param s source string reference + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING //! Set this value as a string by copying from source string. @@ -1780,7 +1794,7 @@ public: \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ - GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } #endif //@} diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index fefc001..307e1b0 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -857,9 +857,46 @@ TEST(Value, String) { } // Issue 226: Value of string type should not point to NULL -TEST(Value, SetStringNullException) { - Value v; - EXPECT_THROW(v.SetString(0, 0), AssertException); +TEST(Value, SetStringNull) { + + MemoryPoolAllocator<> allocator; + const char* nullPtr = 0; + { + // Construction with string type creates empty string + Value v(kStringType); + EXPECT_NE(v.GetString(), nullPtr); // non-null string returned + EXPECT_EQ(v.GetStringLength(), 0u); + + // Construction from/setting to null without length not allowed + EXPECT_THROW(Value(StringRef(nullPtr)), AssertException); + EXPECT_THROW(Value(StringRef(nullPtr), allocator), AssertException); + EXPECT_THROW(v.SetString(nullPtr, allocator), AssertException); + + // Non-empty length with null string is not allowed + EXPECT_THROW(v.SetString(nullPtr, 17u), AssertException); + EXPECT_THROW(v.SetString(nullPtr, 42u, allocator), AssertException); + + // Setting to null string with empty length is allowed + v.SetString(nullPtr, 0u); + EXPECT_NE(v.GetString(), nullPtr); // non-null string returned + EXPECT_EQ(v.GetStringLength(), 0u); + + v.SetNull(); + v.SetString(nullPtr, 0u, allocator); + EXPECT_NE(v.GetString(), nullPtr); // non-null string returned + EXPECT_EQ(v.GetStringLength(), 0u); + } + // Construction with null string and empty length is allowed + { + Value v(nullPtr,0u); + EXPECT_NE(v.GetString(), nullPtr); // non-null string returned + EXPECT_EQ(v.GetStringLength(), 0u); + } + { + Value v(nullPtr, 0u, allocator); + EXPECT_NE(v.GetString(), nullPtr); // non-null string returned + EXPECT_EQ(v.GetStringLength(), 0u); + } } template From 7161894f4069879642aef9eae8b6e63fbd36cfd8 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Mon, 10 Jul 2017 21:32:16 +0200 Subject: [PATCH 034/128] travis-doxygen.sh: upgrade to Doxygen 1.8.13 * Upgrade to the latest Doxygen version 1.8.13 * Drop unused variable DOXYGEN_BIN * Reenable --single-branch (travis-ci/travis-ci#5225 is closed) --- travis-doxygen.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/travis-doxygen.sh b/travis-doxygen.sh index 31a50cf..e5c0320 100755 --- a/travis-doxygen.sh +++ b/travis-doxygen.sh @@ -4,10 +4,9 @@ set -e -DOXYGEN_VER=doxygen-1.8.7 +DOXYGEN_VER=doxygen-1.8.13 DOXYGEN_TAR=${DOXYGEN_VER}.linux.bin.tar.gz DOXYGEN_URL="http://ftp.stack.nl/pub/users/dimitri/${DOXYGEN_TAR}" -DOXYGEN_BIN="/usr/local/bin/doxygen" : ${GITHUB_REPO:="miloyip/rapidjson"} GITHUB_HOST="github.com" @@ -66,7 +65,7 @@ gh_pages_prepare() [ ! -d "html" ] || \ abort "Doxygen target directory already exists." git --version - git clone -b gh-pages "${GITHUB_CLONE}" html + git clone --single-branch -b gh-pages "${GITHUB_CLONE}" html cd html # setup git config (with defaults) git config user.name "${GIT_NAME-travis}" From 70171f97903752cdf4c910b94b5ee0e06570bb41 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Mon, 10 Jul 2017 22:32:18 +0200 Subject: [PATCH 035/128] GenericStringRef: move assert out of expression --- include/rapidjson/document.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 06451ad..3169bd4 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -308,7 +308,7 @@ struct GenericStringRef { */ #endif explicit GenericStringRef(const CharType* str) - : s(str), length(((RAPIDJSON_ASSERT(str != 0)), internal::StrLen(str))) {} + : s(str), length(NotNullStrLen(str)) {} //! Create constant string reference from pointer and length #ifndef __clang__ // -Wdocumentation @@ -331,6 +331,11 @@ struct GenericStringRef { const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: + SizeType NotNullStrLen(const CharType* str) { + RAPIDJSON_ASSERT(str != 0); + return internal::StrLen(str); + } + /// Empty string - used when passing in a NULL pointer static const Ch emptyString[]; From fcd2e1f60cecc00d414821987b2d3d02dbd593df Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 13 Jul 2017 16:07:36 +0800 Subject: [PATCH 036/128] Fix #1017 allOf keyword fail with Writer handler Gave up using static binding for null handler, because it cannot be used with arbitrary handler type. Change `OutputHandler handler_` to pointer type. --- include/rapidjson/schema.h | 26 ++++++++------------------ test/unittest/schematest.cpp | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index dd57edb..abcf1a1 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -1594,7 +1594,7 @@ public: ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), - outputHandler_(CreateNullHandler()), + outputHandler_(0), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) @@ -1622,8 +1622,7 @@ public: ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), - outputHandler_(outputHandler), - nullHandler_(0), + outputHandler_(&outputHandler), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) @@ -1634,10 +1633,6 @@ public: //! Destructor. ~GenericSchemaValidator() { Reset(); - if (nullHandler_) { - nullHandler_->~OutputHandler(); - StateAllocator::Free(nullHandler_); - } RAPIDJSON_DELETE(ownStateAllocator_); } @@ -1699,7 +1694,7 @@ RAPIDJSON_MULTILINEMACRO_END } #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ - return valid_ = EndValue() && outputHandler_.method arg2 + return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2) #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ @@ -1721,7 +1716,7 @@ RAPIDJSON_MULTILINEMACRO_END bool StartObject() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); - return valid_ = outputHandler_.StartObject(); + return valid_ = !outputHandler_ || outputHandler_->StartObject(); } bool Key(const Ch* str, SizeType len, bool copy) { @@ -1729,7 +1724,7 @@ RAPIDJSON_MULTILINEMACRO_END AppendToken(str, len); if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); - return valid_ = outputHandler_.Key(str, len, copy); + return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); } bool EndObject(SizeType memberCount) { @@ -1742,7 +1737,7 @@ RAPIDJSON_MULTILINEMACRO_END bool StartArray() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); - return valid_ = outputHandler_.StartArray(); + return valid_ = !outputHandler_ || outputHandler_->StartArray(); } bool EndArray(SizeType elementCount) { @@ -1815,7 +1810,7 @@ private: ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), - outputHandler_(CreateNullHandler()), + outputHandler_(0), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(depth) @@ -1929,10 +1924,6 @@ private: Context& CurrentContext() { return *schemaStack_.template Top(); } const Context& CurrentContext() const { return *schemaStack_.template Top(); } - OutputHandler& CreateNullHandler() { - return *(nullHandler_ = new (GetStateAllocator().Malloc(sizeof(OutputHandler))) OutputHandler); - } - static const size_t kDefaultSchemaStackCapacity = 1024; static const size_t kDefaultDocumentStackCapacity = 256; const SchemaDocumentType* schemaDocument_; @@ -1941,8 +1932,7 @@ private: 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) - OutputHandler& outputHandler_; - OutputHandler* nullHandler_; + OutputHandler* outputHandler_; bool valid_; #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth_; diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index e79fec2..9b99ba8 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -1329,6 +1329,25 @@ TEST(SchemaValidator, Issue825) { VALIDATE(s, "{ \"item\": \"hello\" }", true); } +TEST(SchemaValidator, Issue1017_allOfHandler) { + Document sd; + sd.Parse("{\"allOf\": [{\"type\": \"object\",\"properties\": {\"cyanArray2\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}}},{\"type\": \"object\",\"properties\": {\"blackArray\": {\"type\": \"array\",\"items\": { \"type\": \"string\" }}},\"required\": [ \"blackArray\" ]}]}"); + SchemaDocument s(sd); + StringBuffer sb; + Writer writer(sb); + GenericSchemaValidator > validator(s, writer); + EXPECT_TRUE(validator.StartObject()); + EXPECT_TRUE(validator.Key("cyanArray2", 10, false)); + EXPECT_TRUE(validator.StartArray()); + EXPECT_TRUE(validator.EndArray(0)); + EXPECT_TRUE(validator.Key("blackArray", 10, false)); + EXPECT_TRUE(validator.StartArray()); + EXPECT_TRUE(validator.EndArray(0)); + EXPECT_TRUE(validator.EndObject(0)); + EXPECT_TRUE(validator.IsValid()); + EXPECT_STREQ("{\"cyanArray2\":[],\"blackArray\":[]}", sb.GetString()); +} + #ifdef __clang__ RAPIDJSON_DIAG_POP #endif From 707fd36afa54f44d4635fde0107eac1c2f4e8649 Mon Sep 17 00:00:00 2001 From: Bart Muzzin Date: Tue, 25 Jul 2017 22:13:26 -0400 Subject: [PATCH 037/128] Issue #1028: Visual Studio natvis file. --- contrib/natvis/LICENSE | 45 +++++++++++++++++++++++++++++++++ contrib/natvis/README.md | 7 +++++ contrib/natvis/rapidjson.natvis | 38 ++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 contrib/natvis/LICENSE create mode 100644 contrib/natvis/README.md create mode 100644 contrib/natvis/rapidjson.natvis diff --git a/contrib/natvis/LICENSE b/contrib/natvis/LICENSE new file mode 100644 index 0000000..f57da96 --- /dev/null +++ b/contrib/natvis/LICENSE @@ -0,0 +1,45 @@ +The MIT License (MIT) + +Copyright (c) 2017 Bart Muzzin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Derived from: + +The MIT License (MIT) + +Copyright (c) 2015 mojmir svoboda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/contrib/natvis/README.md b/contrib/natvis/README.md new file mode 100644 index 0000000..9685c7f --- /dev/null +++ b/contrib/natvis/README.md @@ -0,0 +1,7 @@ +# rapidjson.natvis + +This file can be used as a [Visual Studio Visualizer](https://docs.microsoft.com/en-gb/visualstudio/debugger/create-custom-views-of-native-objects) to aid in visualizing rapidjson structures within the Visual Studio debugger. Natvis visualizers are supported in Visual Studio 2012 and later. To install, copy the file into this directory: + +`%USERPROFILE%\Documents\Visual Studio 2012\Visualizers` + +Each version of Visual Studio has a similar directory, it must be copied into each directory to be used with that particular version. In Visual Studio 2015 and later, this can be done without restarting Visual Studio (a new debugging session must be started). diff --git a/contrib/natvis/rapidjson.natvis b/contrib/natvis/rapidjson.natvis new file mode 100644 index 0000000..a804b7b --- /dev/null +++ b/contrib/natvis/rapidjson.natvis @@ -0,0 +1,38 @@ + + + + + null + true + false + {data_.ss.str} + {(const char*)((size_t)data_.s.str & 0x0000FFFFFFFFFFFF)} + {data_.n.i.i} + {data_.n.u.u} + {data_.n.i64} + {data_.n.u64} + {data_.n.d} + Object members={data_.o.size} + Array members={data_.a.size} + + data_.o.size + data_.o.capacity + + data_.o.size + + (rapidjson::GenericMember<$T1,$T2>*)(((size_t)data_.o.members) & 0x0000FFFFFFFFFFFF) + + + data_.a.size + data_.a.capacity + + data_.a.size + + (rapidjson::GenericValue<$T1,$T2>*)(((size_t)data_.a.elements) & 0x0000FFFFFFFFFFFF) + + + + + + + From 7c1f20825374390e2a1005e0bc488a3b99c873d0 Mon Sep 17 00:00:00 2001 From: bluehero Date: Sat, 5 Aug 2017 16:53:45 +0800 Subject: [PATCH 038/128] modify --- include/rapidjson/document.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 3169bd4..f5c02d6 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2168,6 +2168,10 @@ public: } #endif + // Allow assignment from ValueType. + // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. + using ValueType::operator=; + //! Exchange the contents of this document with those of another. /*! \param rhs Another document. @@ -2183,6 +2187,10 @@ public: return *this; } + // Allow Swap from ValueType. + // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. + using ValueType::Swap; + //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: From 9eb7bf895c124fcf76877b173f6930a40e71e0a8 Mon Sep 17 00:00:00 2001 From: bluehero Date: Sat, 5 Aug 2017 18:12:44 +0800 Subject: [PATCH 039/128] add unittest --- test/unittest/documenttest.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 0ca5801..55d828a 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -290,6 +290,14 @@ TEST(Document, ParseStream_AutoUTFInputStream) { EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); } +TEST(Document, Assignment) { + Value x(1234); + Document d; + d = x; + EXPECT_TRUE(x.IsNull()); // move semantic + EXPECT_EQ(1234, d.GetInt()); +} + TEST(Document, Swap) { Document d1; Document::AllocatorType& a = d1.GetAllocator(); @@ -300,7 +308,14 @@ TEST(Document, Swap) { o.SetObject().AddMember("a", 1, a); // Swap between Document and Value - // d1.Swap(o); // doesn't compile + d1.Swap(o); + EXPECT_TRUE(d1.IsObject()); + EXPECT_TRUE(o.IsArray()); + + d1.Swap(o); + EXPECT_TRUE(d1.IsArray()); + EXPECT_TRUE(o.IsObject()); + o.Swap(d1); EXPECT_TRUE(d1.IsObject()); EXPECT_TRUE(o.IsArray()); From 8ba1f84f47a3c5761be86884f77421a73c9a38fe Mon Sep 17 00:00:00 2001 From: bluehero Date: Sat, 5 Aug 2017 20:39:31 +0800 Subject: [PATCH 040/128] modify unittest --- test/unittest/documenttest.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 55d828a..9ff8096 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -290,14 +290,6 @@ TEST(Document, ParseStream_AutoUTFInputStream) { EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); } -TEST(Document, Assignment) { - Value x(1234); - Document d; - d = x; - EXPECT_TRUE(x.IsNull()); // move semantic - EXPECT_EQ(1234, d.GetInt()); -} - TEST(Document, Swap) { Document d1; Document::AllocatorType& a = d1.GetAllocator(); @@ -667,13 +659,20 @@ TYPED_TEST(DocumentMove, MoveAssignmentStack) { #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS -// Issue 22: Memory corruption via operator= +// Issue 22: Memory corruption via operator= from Document // Fixed by making unimplemented assignment operator private. -//TEST(Document, Assignment) { +// Prohibit assignment from Document, But allow assignment from Value +TEST(Document, Assignment) { // Document d1; // Document d2; // d1 = d2; -//} + + Value x(1234); + Document d; + d = x; + EXPECT_TRUE(x.IsNull()); // move semantic + EXPECT_EQ(1234, d.GetInt()); +} #ifdef __clang__ RAPIDJSON_DIAG_POP From 5fb06596a93f62e98fb9900dac2f1c97e5981549 Mon Sep 17 00:00:00 2001 From: bluehero Date: Mon, 7 Aug 2017 11:44:27 +0800 Subject: [PATCH 041/128] modify --- include/rapidjson/document.h | 4 +--- test/unittest/documenttest.cpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index f5c02d6..869667a 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2168,8 +2168,7 @@ public: } #endif - // Allow assignment from ValueType. - // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. + // Allow assignment like a ValueType. using ValueType::operator=; //! Exchange the contents of this document with those of another. @@ -2188,7 +2187,6 @@ public: } // Allow Swap from ValueType. - // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. using ValueType::Swap; //! free-standing swap function helper diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 9ff8096..0d08b25 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -661,17 +661,25 @@ TYPED_TEST(DocumentMove, MoveAssignmentStack) { // Issue 22: Memory corruption via operator= from Document // Fixed by making unimplemented assignment operator private. -// Prohibit assignment from Document, But allow assignment from Value +// Prohibit assignment from Document. +// But allow assignment from ValueType/int/double/..., like a ValueType TEST(Document, Assignment) { // Document d1; // Document d2; // d1 = d2; - Value x(1234); Document d; + + Value x(1234); d = x; EXPECT_TRUE(x.IsNull()); // move semantic EXPECT_EQ(1234, d.GetInt()); + + d = 1; + EXPECT_EQ(1, d.GetInt()); + + d = 12.34; + EXPECT_NEAR(12.34, d.GetDouble(), 0.0); } #ifdef __clang__ From c831675026cc2c0a7b3581d8b0e0fe4eedd8d78f Mon Sep 17 00:00:00 2001 From: bluehero Date: Mon, 7 Aug 2017 11:58:37 +0800 Subject: [PATCH 042/128] modify --- include/rapidjson/document.h | 6 ++---- test/unittest/documenttest.cpp | 21 +++------------------ 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 869667a..f55b7d3 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2168,9 +2168,6 @@ public: } #endif - // Allow assignment like a ValueType. - using ValueType::operator=; - //! Exchange the contents of this document with those of another. /*! \param rhs Another document. @@ -2186,7 +2183,8 @@ public: return *this; } - // Allow Swap from ValueType. + // Allow Swap with ValueType. + // Refer to Effective C++/Item 33: Avoid hiding inherited names. using ValueType::Swap; //! free-standing swap function helper diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 0d08b25..5429802 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -659,28 +659,13 @@ TYPED_TEST(DocumentMove, MoveAssignmentStack) { #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS -// Issue 22: Memory corruption via operator= from Document +// Issue 22: Memory corruption via operator= // Fixed by making unimplemented assignment operator private. -// Prohibit assignment from Document. -// But allow assignment from ValueType/int/double/..., like a ValueType -TEST(Document, Assignment) { +//TEST(Document, Assignment) { // Document d1; // Document d2; // d1 = d2; - - Document d; - - Value x(1234); - d = x; - EXPECT_TRUE(x.IsNull()); // move semantic - EXPECT_EQ(1234, d.GetInt()); - - d = 1; - EXPECT_EQ(1, d.GetInt()); - - d = 12.34; - EXPECT_NEAR(12.34, d.GetDouble(), 0.0); -} +//} #ifdef __clang__ RAPIDJSON_DIAG_POP From f9004b90c555f9374d3f6e4d462e4abbce3b00a8 Mon Sep 17 00:00:00 2001 From: bluehero Date: Mon, 7 Aug 2017 13:09:22 +0800 Subject: [PATCH 043/128] modify --- include/rapidjson/document.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index f55b7d3..3133a2f 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2184,7 +2184,7 @@ public: } // Allow Swap with ValueType. - // Refer to Effective C++/Item 33: Avoid hiding inherited names. + // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. using ValueType::Swap; //! free-standing swap function helper From f91405801f88533c609d95f2fcc2d88811544d35 Mon Sep 17 00:00:00 2001 From: Minmin Gong Date: Thu, 31 Aug 2017 23:16:30 -0700 Subject: [PATCH 044/128] Specifies the endian of msvc ARM64 configuration. --- include/rapidjson/rapidjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 57ab851..5716fdc 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -241,7 +241,7 @@ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(_MSC_VER) && defined(_M_ARM) +# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN From 9ce6a7ebb8a467b7e796b010d5acb61da7679ff1 Mon Sep 17 00:00:00 2001 From: Crunkle Date: Sat, 2 Sep 2017 21:03:03 +0100 Subject: [PATCH 045/128] Fix processor check when empty --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b90c87..3ccc374 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ if(CCACHE_FOUND) endif(CCACHE_FOUND) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "powerpc" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le") + if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") else() #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. @@ -80,7 +80,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") endif() endif() elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "powerpc" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le") + if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") else() #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. From bbdf5d1d4b40891c82e5c1946d32dfc841926066 Mon Sep 17 00:00:00 2001 From: Christopher Warrington Date: Tue, 5 Sep 2017 16:58:09 -0700 Subject: [PATCH 046/128] Fix Windows doc build MSBuild error MSB6001 When using a MSBuild-based CMake generator like 'Visual Studio 15 2017 Win64', the doc build was failing with the error 'MSB6001: Invalid command line switch for "cmd.exe". Illegal characters in path.' This was due to the dependency on Doxyfile*, which wasn't expanded by CMake. The fix is to expand this glob in CMake before specifying the custom command's dependencies. Partial fix for https://github.com/miloyip/rapidjson/issues/622 --- doc/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index c1f165a..c5345ba 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -10,11 +10,13 @@ ELSE() CONFIGURE_FILE(Doxyfile.in Doxyfile @ONLY) CONFIGURE_FILE(Doxyfile.zh-cn.in Doxyfile.zh-cn @ONLY) + file(GLOB DOXYFILES ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile*) + add_custom_command(OUTPUT html COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.zh-cn COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/html - DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile* + DEPENDS ${MARKDOWN_DOC} ${SOURCES} ${DOXYFILES} WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../ ) From 6e38649ec61e5f4f382c257a6b27698bb55eff61 Mon Sep 17 00:00:00 2001 From: Christopher Warrington Date: Tue, 5 Sep 2017 18:23:28 -0700 Subject: [PATCH 047/128] Guard against min/max being macros in document.h Sometimes, particularly when Microsoft's windows.h is included, min/max are defined as macros, interfering with use of std::numeric_limits::min() and the like. To guard against this, the function name is wrapped in an extra set of parenthesis, which inhibits function-style macro expansion. --- include/rapidjson/document.h | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 3133a2f..191582e 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -29,14 +29,6 @@ RAPIDJSON_DIAG_PUSH #ifdef _MSC_VER RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data -#ifdef _MINWINDEF_ // see: http://stackoverflow.com/questions/22744262/cant-call-stdmax-because-minwindef-h-defines-max -#ifndef NOMINMAX -#pragma push_macro("min") -#pragma push_macro("max") -#undef min -#undef max -#endif -#endif #endif #ifdef __clang__ @@ -1018,14 +1010,14 @@ public: uint64_t u = GetUint64(); volatile double d = static_cast(u); return (d >= 0.0) - && (d < static_cast(std::numeric_limits::max())) + && (d < static_cast((std::numeric_limits::max)())) && (u == static_cast(d)); } if (IsInt64()) { int64_t i = GetInt64(); volatile double d = static_cast(i); - return (d >= static_cast(std::numeric_limits::min())) - && (d < static_cast(std::numeric_limits::max())) + return (d >= static_cast((std::numeric_limits::min)())) + && (d < static_cast((std::numeric_limits::max)())) && (i == static_cast(d)); } return true; // double, int, uint are always lossless @@ -1042,8 +1034,8 @@ public: bool IsLosslessFloat() const { if (!IsNumber()) return false; double a = GetDouble(); - if (a < static_cast(-std::numeric_limits::max()) - || a > static_cast(std::numeric_limits::max())) + if (a < static_cast(-(std::numeric_limits::max)()) + || a > static_cast((std::numeric_limits::max)())) return false; double b = static_cast(static_cast(a)); return a >= b && a <= b; // Prevent -Wfloat-equal @@ -2616,12 +2608,6 @@ private: }; RAPIDJSON_NAMESPACE_END -#ifdef _MINWINDEF_ // see: http://stackoverflow.com/questions/22744262/cant-call-stdmax-because-minwindef-h-defines-max -#ifndef NOMINMAX -#pragma pop_macro("min") -#pragma pop_macro("max") -#endif -#endif RAPIDJSON_DIAG_POP #endif // RAPIDJSON_DOCUMENT_H_ From e4c0ecf86b7db94014cde331cd43b6443f993be7 Mon Sep 17 00:00:00 2001 From: Christopher Warrington Date: Tue, 5 Sep 2017 18:27:02 -0700 Subject: [PATCH 048/128] Guard against min/max macros in tests too --- test/unittest/itoatest.cpp | 4 ++-- test/unittest/readertest.cpp | 2 +- test/unittest/strtodtest.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unittest/itoatest.cpp b/test/unittest/itoatest.cpp index 2f66bed..f41edeb 100644 --- a/test/unittest/itoatest.cpp +++ b/test/unittest/itoatest.cpp @@ -70,8 +70,8 @@ template static void Verify(void(*f)(T, char*), char* (*g)(T, char*)) { // Boundary cases VerifyValue(0, f, g); - VerifyValue(std::numeric_limits::min(), f, g); - VerifyValue(std::numeric_limits::max(), f, g); + VerifyValue((std::numeric_limits::min)(), f, g); + VerifyValue((std::numeric_limits::max)(), f, g); // 2^n - 1, 2^n, 10^n - 1, 10^n until overflow for (int power = 2; power <= 10; power += 8) { diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 5078f52..dad33d6 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -415,7 +415,7 @@ TEST(Reader, ParseNumber_NormalPrecisionError) { uint64_t bias1 = e.ToBias(); uint64_t bias2 = a.ToBias(); double ulp = static_cast(bias1 >= bias2 ? bias1 - bias2 : bias2 - bias1); - ulpMax = std::max(ulpMax, ulp); + ulpMax = (std::max)(ulpMax, ulp); ulpSum += ulp; } printf("ULP Average = %g, Max = %g \n", ulpSum / count, ulpMax); diff --git a/test/unittest/strtodtest.cpp b/test/unittest/strtodtest.cpp index cde836c..807f887 100644 --- a/test/unittest/strtodtest.cpp +++ b/test/unittest/strtodtest.cpp @@ -91,7 +91,7 @@ TEST(Strtod, CheckApproximationCase) { } // Remove common power of two factor from all three scaled values - int common_Exp2 = std::min(dS_Exp2, std::min(bS_Exp2, hS_Exp2)); + int common_Exp2 = (std::min)(dS_Exp2, (std::min)(bS_Exp2, hS_Exp2)); dS_Exp2 -= common_Exp2; bS_Exp2 -= common_Exp2; hS_Exp2 -= common_Exp2; From a683902b2c15e32bfac04afc1d5248466c755c9e Mon Sep 17 00:00:00 2001 From: Christopher Warrington Date: Tue, 5 Sep 2017 16:03:54 -0700 Subject: [PATCH 049/128] Assert Type enum lower bound as well --- include/rapidjson/document.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 191582e..93b091f 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -605,7 +605,7 @@ public: kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; - RAPIDJSON_ASSERT(type <= kNumberType); + RAPIDJSON_ASSERT(type >= kNullType && type <= kNumberType); data_.f.flags = defaultFlags[type]; // Use ShortString to store empty string. From 4a2f2729f1313a7150d1275185f4888224a48753 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 13 Sep 2017 17:03:23 +0800 Subject: [PATCH 050/128] Change from miloyip/rapidjson to Tencent/rapidjson --- .travis.yml | 2 +- CHANGELOG.md | 12 +++++----- RapidJSON.pc.in | 2 +- doc/faq.md | 6 ++--- doc/faq.zh-cn.md | 6 ++--- doc/features.md | 2 +- doc/features.zh-cn.md | 2 +- doc/internals.md | 2 +- doc/internals.zh-cn.md | 2 +- doc/misc/header.html | 2 +- doc/npm.md | 2 +- doc/performance.md | 4 ++-- doc/performance.zh-cn.md | 4 ++-- library.json | Bin 355 -> 355 bytes package.json | Bin 561 -> 561 bytes rapidjson.autopkg | 6 ++--- readme.md | 44 +++++++++++++++++----------------- readme.zh-cn.md | 44 +++++++++++++++++----------------- test/unittest/pointertest.cpp | 2 +- test/unittest/readertest.cpp | 2 +- travis-doxygen.sh | 2 +- 21 files changed, 74 insertions(+), 74 deletions(-) diff --git a/.travis.yml b/.travis.yml index 38f3a98..df821a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ env: - CCACHE_MAXSIZE=100M - ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit - ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit - - GITHUB_REPO='miloyip/rapidjson' + - GITHUB_REPO='Tencent/rapidjson' - secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk=" before_install: diff --git a/CHANGELOG.md b/CHANGELOG.md index 0205e7b..c9d603c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,7 +109,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [1.0.0] - 2015-04-22 ### Added -* 100% [Coverall](https://coveralls.io/r/miloyip/rapidjson?branch=master) coverage. +* 100% [Coverall](https://coveralls.io/r/Tencent/rapidjson?branch=master) coverage. * Version macros (#311) ### Fixed @@ -151,8 +151,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## 0.1 - 2011-11-18 -[Unreleased]: https://github.com/miloyip/rapidjson/compare/v1.1.0...HEAD -[1.1.0]: https://github.com/miloyip/rapidjson/compare/v1.0.2...v1.1.0 -[1.0.2]: https://github.com/miloyip/rapidjson/compare/v1.0.1...v1.0.2 -[1.0.1]: https://github.com/miloyip/rapidjson/compare/v1.0.0...v1.0.1 -[1.0.0]: https://github.com/miloyip/rapidjson/compare/v1.0-beta...v1.0.0 +[Unreleased]: https://github.com/Tencent/rapidjson/compare/v1.1.0...HEAD +[1.1.0]: https://github.com/Tencent/rapidjson/compare/v1.0.2...v1.1.0 +[1.0.2]: https://github.com/Tencent/rapidjson/compare/v1.0.1...v1.0.2 +[1.0.1]: https://github.com/Tencent/rapidjson/compare/v1.0.0...v1.0.1 +[1.0.0]: https://github.com/Tencent/rapidjson/compare/v1.0-beta...v1.0.0 diff --git a/RapidJSON.pc.in b/RapidJSON.pc.in index 7467f97..6afb079 100644 --- a/RapidJSON.pc.in +++ b/RapidJSON.pc.in @@ -3,5 +3,5 @@ includedir=@INCLUDE_INSTALL_DIR@ Name: @PROJECT_NAME@ Description: A fast JSON parser/generator for C++ with both SAX/DOM style API Version: @LIB_VERSION_STRING@ -URL: https://github.com/miloyip/rapidjson +URL: https://github.com/Tencent/rapidjson Cflags: -I${includedir} diff --git a/doc/faq.md b/doc/faq.md index 4946cfe..74d770d 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -18,7 +18,7 @@ 4. Is RapidJSON free? - Yes, it is free under MIT license. It can be used in commercial applications. Please check the details in [license.txt](https://github.com/miloyip/rapidjson/blob/master/license.txt). + Yes, it is free under MIT license. It can be used in commercial applications. Please check the details in [license.txt](https://github.com/Tencent/rapidjson/blob/master/license.txt). 5. Is RapidJSON small? What are its dependencies? @@ -44,7 +44,7 @@ 10. How RapidJSON is tested? - RapidJSON contains a unit test suite for automatic testing. [Travis](https://travis-ci.org/miloyip/rapidjson/)(for Linux) and [AppVeyor](https://ci.appveyor.com/project/miloyip/rapidjson/)(for Windows) will compile and run the unit test suite for all modifications. The test process also uses Valgrind (in Linux) to detect memory leaks. + RapidJSON contains a unit test suite for automatic testing. [Travis](https://travis-ci.org/Tencent/rapidjson/)(for Linux) and [AppVeyor](https://ci.appveyor.com/project/Tencent/rapidjson/)(for Windows) will compile and run the unit test suite for all modifications. The test process also uses Valgrind (in Linux) to detect memory leaks. 11. Is RapidJSON well documented? @@ -70,7 +70,7 @@ 3. Does RapidJSON support relaxed syntax? - Currently no. RapidJSON only support the strict standardized format. Support on related syntax is under discussion in this [issue](https://github.com/miloyip/rapidjson/issues/36). + Currently no. RapidJSON only support the strict standardized format. Support on related syntax is under discussion in this [issue](https://github.com/Tencent/rapidjson/issues/36). ## DOM and SAX diff --git a/doc/faq.zh-cn.md b/doc/faq.zh-cn.md index 307b02f..f279acf 100644 --- a/doc/faq.zh-cn.md +++ b/doc/faq.zh-cn.md @@ -18,7 +18,7 @@ 4. RapidJSON 是免费的么? - 是的,它在 MIT 特許條款下免费。它可用于商业软件。详情请参看 [license.txt](https://github.com/miloyip/rapidjson/blob/master/license.txt)。 + 是的,它在 MIT 特許條款下免费。它可用于商业软件。详情请参看 [license.txt](https://github.com/Tencent/rapidjson/blob/master/license.txt)。 5. RapidJSON 很小么?它有何依赖? @@ -44,7 +44,7 @@ 10. RapidJSON 是如何被测试的? - RapidJSON 包含一组单元测试去执行自动测试。[Travis](https://travis-ci.org/miloyip/rapidjson/)(供 Linux 平台)及 [AppVeyor](https://ci.appveyor.com/project/miloyip/rapidjson/)(供 Windows 平台)会对所有修改进行编译及执行单元测试。在 Linux 下还会使用 Valgrind 去检测内存泄漏。 + RapidJSON 包含一组单元测试去执行自动测试。[Travis](https://travis-ci.org/Tencent/rapidjson/)(供 Linux 平台)及 [AppVeyor](https://ci.appveyor.com/project/Tencent/rapidjson/)(供 Windows 平台)会对所有修改进行编译及执行单元测试。在 Linux 下还会使用 Valgrind 去检测内存泄漏。 11. RapidJSON 是否有完整的文档? @@ -70,7 +70,7 @@ 3. RapidJSON 是否支持宽松的语法? - 现时不支持。RapidJSON 只支持严格的标准格式。宽松语法现时在这 [issue](https://github.com/miloyip/rapidjson/issues/36) 中进行讨论。 + 现时不支持。RapidJSON 只支持严格的标准格式。宽松语法现时在这 [issue](https://github.com/Tencent/rapidjson/issues/36) 中进行讨论。 ## DOM 与 SAX diff --git a/doc/features.md b/doc/features.md index 732fb21..0d79e7f 100644 --- a/doc/features.md +++ b/doc/features.md @@ -29,7 +29,7 @@ * Single line (`// ...`) and multiple line (`/* ... */`) comments (`kParseCommentsFlag`). * Trailing commas at the end of objects and arrays (`kParseTrailingCommasFlag`). * `NaN`, `Inf`, `Infinity`, `-Inf` and `-Infinity` as `double` values (`kParseNanAndInfFlag`) -* [NPM compliant](http://github.com/miloyip/rapidjson/blob/master/doc/npm.md). +* [NPM compliant](http://github.com/Tencent/rapidjson/blob/master/doc/npm.md). ## Unicode diff --git a/doc/features.zh-cn.md b/doc/features.zh-cn.md index 19908a8..7662cc1 100644 --- a/doc/features.zh-cn.md +++ b/doc/features.zh-cn.md @@ -29,7 +29,7 @@ * 单行(`// ...`)及多行(`/* ... */`) 注释 (`kParseCommentsFlag`)。 * 在对象和数组结束前含逗号 (`kParseTrailingCommasFlag`)。 * `NaN`、`Inf`、`Infinity`、`-Inf` 及 `-Infinity` 作为 `double` 值 (`kParseNanAndInfFlag`) -* [NPM 兼容](https://github.com/miloyip/rapidjson/blob/master/doc/npm.md). +* [NPM 兼容](https://github.com/Tencent/rapidjson/blob/master/doc/npm.md). ## Unicode diff --git a/doc/internals.md b/doc/internals.md index 2fff2d9..9b94d7f 100644 --- a/doc/internals.md +++ b/doc/internals.md @@ -214,7 +214,7 @@ In [Intel® 64 and IA-32 Architectures Optimization Reference Manual This is not feasible as RapidJSON should not enforce such requirement. -To fix this issue, currently the routine process bytes up to the next aligned address. After tha, use aligned read to perform SIMD processing. Also see [#85](https://github.com/miloyip/rapidjson/issues/85). +To fix this issue, currently the routine process bytes up to the next aligned address. After tha, use aligned read to perform SIMD processing. Also see [#85](https://github.com/Tencent/rapidjson/issues/85). ## Local Stream Copy {#LocalStreamCopy} diff --git a/doc/internals.zh-cn.md b/doc/internals.zh-cn.md index 0c8bc06..ca3d297 100644 --- a/doc/internals.zh-cn.md +++ b/doc/internals.zh-cn.md @@ -214,7 +214,7 @@ void SkipWhitespace(InputStream& s) { 对于 RapidJSON 来说,这显然是不可行的,因为 RapidJSON 不应当强迫用户进行内存对齐。 -为了修复这个问题,当前的代码会先按字节处理直到下一个对齐的地址。在这之后,使用对齐读取来进行 SIMD 处理。见 [#85](https://github.com/miloyip/rapidjson/issues/85)。 +为了修复这个问题,当前的代码会先按字节处理直到下一个对齐的地址。在这之后,使用对齐读取来进行 SIMD 处理。见 [#85](https://github.com/Tencent/rapidjson/issues/85)。 ## 局部流拷贝 {#LocalStreamCopy} diff --git a/doc/misc/header.html b/doc/misc/header.html index 2dbe721..a89ba46 100644 --- a/doc/misc/header.html +++ b/doc/misc/header.html @@ -18,7 +18,7 @@ $extrastylesheet
-
+
$searchbox diff --git a/doc/npm.md b/doc/npm.md index 5efa768..6f4e85a 100644 --- a/doc/npm.md +++ b/doc/npm.md @@ -7,7 +7,7 @@ ... "dependencies": { ... - "rapidjson": "git@github.com:miloyip/rapidjson.git" + "rapidjson": "git@github.com:Tencent/rapidjson.git" }, ... "gypfile": true diff --git a/doc/performance.md b/doc/performance.md index 988e799..7b18730 100644 --- a/doc/performance.md +++ b/doc/performance.md @@ -15,12 +15,12 @@ Additionally, you may refer to the following third-party benchmarks. * [json_spirit](https://github.com/cierelabs/json_spirit) * [jsoncpp](http://jsoncpp.sourceforge.net/) * [libjson](http://sourceforge.net/projects/libjson/) - * [rapidjson](https://github.com/miloyip/rapidjson/) + * [rapidjson](https://github.com/Tencent/rapidjson/) * [QJsonDocument](http://qt-project.org/doc/qt-5.0/qtcore/qjsondocument.html) * [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013) * [sajson](https://github.com/chadaustin/sajson) - * [rapidjson](https://github.com/miloyip/rapidjson/) + * [rapidjson](https://github.com/Tencent/rapidjson/) * [vjson](https://code.google.com/p/vjson/) * [YAJL](http://lloyd.github.com/yajl/) * [Jansson](http://www.digip.org/jansson/) diff --git a/doc/performance.zh-cn.md b/doc/performance.zh-cn.md index c20c505..2322c9c 100644 --- a/doc/performance.zh-cn.md +++ b/doc/performance.zh-cn.md @@ -15,12 +15,12 @@ RapidJSON 0.1 版本的性能测试文章位于 [这里](https://code.google.com * [json_spirit](https://github.com/cierelabs/json_spirit) * [jsoncpp](http://jsoncpp.sourceforge.net/) * [libjson](http://sourceforge.net/projects/libjson/) - * [rapidjson](https://github.com/miloyip/rapidjson/) + * [rapidjson](https://github.com/Tencent/rapidjson/) * [QJsonDocument](http://qt-project.org/doc/qt-5.0/qtcore/qjsondocument.html) * [JSON Parser Benchmarking](http://chadaustin.me/2013/01/json-parser-benchmarking/) by Chad Austin (Jan 2013) * [sajson](https://github.com/chadaustin/sajson) - * [rapidjson](https://github.com/miloyip/rapidjson/) + * [rapidjson](https://github.com/Tencent/rapidjson/) * [vjson](https://code.google.com/p/vjson/) * [YAJL](http://lloyd.github.com/yajl/) * [Jansson](http://www.digip.org/jansson/) diff --git a/library.json b/library.json index 21d6bcecf22fd12342f560eae0c540daa713003d..2210fcd61735c8cca63c19534e8df591eda60d58 100644 GIT binary patch delta 33 ocmaFN^q6Ub7o%iIYF=_`UWtBDVnJp~R&jow5|@HPEmtiU0MF73BLDyZ delta 33 ocmaFN^q6Ub7o%iuW=?)(W`TZDVnJp~R&jow5|@HPEmtiU0Mu~{RR910 diff --git a/package.json b/package.json index cc6087a5ca36cfd95aacccceb7c07d909f085f4d..129581a633512e5165e985041339c58f990efc24 100644 GIT binary patch delta 60 zcmdnUvXNy&CL?=DYF=_`UdiMF#uPaFHlvjcR9wF(u^=-gt2jSTxhOR;B{x-xtCkA@ Dmf#g| delta 60 zcmdnUvXNy&CL?=pW=?)(X2IkF#uPaFHlvjcR9wF(u^=-gt2jSTxhOR;B{x-xtCkA@ Dt%nu{ diff --git a/rapidjson.autopkg b/rapidjson.autopkg index 486ad14..cbe5258 100644 --- a/rapidjson.autopkg +++ b/rapidjson.autopkg @@ -5,10 +5,10 @@ nuget { id = rapidjson; version : ${MYVERSION}; title: "rapidjson"; - authors: {"https://github.com/miloyip/rapidjson/releases/tag/v1.1.0"}; + authors: {"https://github.com/Tencent/rapidjson/releases/tag/v1.1.0"}; owners: {"@lsantos (github)"}; - licenseUrl: "https://github.com/miloyip/rapidjson/blob/master/license.txt"; - projectUrl: "https://github.com/miloyip/rapidjson/"; + licenseUrl: "https://github.com/Tencent/rapidjson/blob/master/license.txt"; + projectUrl: "https://github.com/Tencent/rapidjson/"; iconUrl: "https://cdn1.iconfinder.com/data/icons/fatcow/32x32/json.png"; requireLicenseAcceptance:false; summary: @"A fast JSON parser/generator for C++ with both SAX/DOM style API"; diff --git a/readme.md b/readme.md index 2937619..c9e9b1a 100644 --- a/readme.md +++ b/readme.md @@ -8,11 +8,11 @@ Tencent is pleased to support the open source community by making RapidJSON avai Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/) +* [RapidJSON GitHub](https://github.com/Tencent/rapidjson/) * RapidJSON Documentation * [English](http://rapidjson.org/) * [简体中文](http://rapidjson.org/zh-cn/) - * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. + * [GitBook](https://www.gitbook.com/book/Tencent/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. ## Build status @@ -20,12 +20,12 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights | :---------------: | :-----------------: | :-------------------: | | ![lin-badge] | ![win-badge] | ![cov-badge] | -[lin-badge]: https://travis-ci.org/miloyip/rapidjson.svg?branch=master "Travis build status" -[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status" -[win-badge]: https://ci.appveyor.com/api/projects/status/github/miloyip/rapidjson?branch=master&svg=true "AppVeyor build status" -[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status" -[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.svg?branch=master "Coveralls coverage" -[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master "Coveralls coverage" +[lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status" +[lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/github/Tencent/rapidjson?branch=master&svg=true "AppVeyor build status" +[win-link]: https://ci.appveyor.com/project/Tencent/rapidjson/branch/master "AppVeyor build status" +[cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage" +[cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage" ## Introduction @@ -136,25 +136,25 @@ The following diagram shows the process. ![simpledom](doc/diagram/simpledom.png) -More [examples](https://github.com/miloyip/rapidjson/tree/master/example) are available: +More [examples](https://github.com/Tencent/rapidjson/tree/master/example) are available: * DOM API - * [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API. + * [tutorial](https://github.com/Tencent/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API. * SAX API - * [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`. - * [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed. - * [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`. - * [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON. - * [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API. - * [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API. - * [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format. + * [simplereader](https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`. + * [condense](https://github.com/Tencent/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed. + * [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`. + * [capitalize](https://github.com/Tencent/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON. + * [messagereader](https://github.com/Tencent/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API. + * [serialize](https://github.com/Tencent/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API. + * [jsonx](https://github.com/Tencent/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format. * Schema - * [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema. + * [schemavalidator](https://github.com/Tencent/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema. * Advanced - * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings. - * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread. - * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key. - * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`. + * [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings. + * [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread. + * [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key. + * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`. diff --git a/readme.zh-cn.md b/readme.zh-cn.md index 81b84bb..422667b 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -8,11 +8,11 @@ Tencent is pleased to support the open source community by making RapidJSON avai Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/) +* [RapidJSON GitHub](https://github.com/Tencent/rapidjson/) * RapidJSON 文档 * [English](http://rapidjson.org/) * [简体中文](http://rapidjson.org/zh-cn/) - * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 + * [GitBook](https://www.gitbook.com/book/Tencent/rapidjson/) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 ## Build 状态 @@ -20,12 +20,12 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights | :---------------: | :-----------------: | :-------------------: | | ![lin-badge] | ![win-badge] | ![cov-badge] | -[lin-badge]: https://travis-ci.org/miloyip/rapidjson.svg?branch=master "Travis build status" -[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status" -[win-badge]: https://ci.appveyor.com/api/projects/status/github/miloyip/rapidjson?branch=master&svg=true "AppVeyor build status" -[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status" -[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.svg?branch=master "Coveralls coverage" -[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master "Coveralls coverage" +[lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status" +[lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/github/Tencent/rapidjson?branch=master&svg=true "AppVeyor build status" +[win-link]: https://ci.appveyor.com/project/Tencent/rapidjson/branch/master "AppVeyor build status" +[cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage" +[cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage" ## 简介 @@ -128,25 +128,25 @@ int main() { ![simpledom](doc/diagram/simpledom.png) -还有许多 [例子](https://github.com/miloyip/rapidjson/tree/master/example) 可供参考: +还有许多 [例子](https://github.com/Tencent/rapidjson/tree/master/example) 可供参考: * DOM API - * [tutorial](https://github.com/miloyip/rapidjson/blob/master/example/tutorial/tutorial.cpp): DOM API 的基本使用方法。 + * [tutorial](https://github.com/Tencent/rapidjson/blob/master/example/tutorial/tutorial.cpp): DOM API 的基本使用方法。 * SAX API - * [simplereader](https://github.com/miloyip/rapidjson/blob/master/example/simplereader/simplereader.cpp): 使用 `Reader` 解析 JSON 时,打印所有 SAX 事件。 - * [condense](https://github.com/miloyip/rapidjson/blob/master/example/condense/condense.cpp): 移除 JSON 中所有空白符的命令行工具。 - * [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp): 为 JSON 加入缩进与换行的命令行工具,当中使用了 `PrettyWriter`。 - * [capitalize](https://github.com/miloyip/rapidjson/blob/master/example/capitalize/capitalize.cpp): 把 JSON 中所有字符串改为大写的命令行工具。 - * [messagereader](https://github.com/miloyip/rapidjson/blob/master/example/messagereader/messagereader.cpp): 使用 SAX API 去解析一个 JSON 报文。 - * [serialize](https://github.com/miloyip/rapidjson/blob/master/example/serialize/serialize.cpp): 使用 SAX API 去序列化 C++ 对象,生成 JSON。 - * [jsonx](https://github.com/miloyip/rapidjson/blob/master/example/jsonx/jsonx.cpp): 实现了一个 `JsonxWriter`,它能把 SAX 事件写成 [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html)(一种 XML)格式。这个例子是把 JSON 输入转换成 JSONx 格式的命令行工具。 + * [simplereader](https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp): 使用 `Reader` 解析 JSON 时,打印所有 SAX 事件。 + * [condense](https://github.com/Tencent/rapidjson/blob/master/example/condense/condense.cpp): 移除 JSON 中所有空白符的命令行工具。 + * [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp): 为 JSON 加入缩进与换行的命令行工具,当中使用了 `PrettyWriter`。 + * [capitalize](https://github.com/Tencent/rapidjson/blob/master/example/capitalize/capitalize.cpp): 把 JSON 中所有字符串改为大写的命令行工具。 + * [messagereader](https://github.com/Tencent/rapidjson/blob/master/example/messagereader/messagereader.cpp): 使用 SAX API 去解析一个 JSON 报文。 + * [serialize](https://github.com/Tencent/rapidjson/blob/master/example/serialize/serialize.cpp): 使用 SAX API 去序列化 C++ 对象,生成 JSON。 + * [jsonx](https://github.com/Tencent/rapidjson/blob/master/example/jsonx/jsonx.cpp): 实现了一个 `JsonxWriter`,它能把 SAX 事件写成 [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html)(一种 XML)格式。这个例子是把 JSON 输入转换成 JSONx 格式的命令行工具。 * Schema API - * [schemavalidator](https://github.com/miloyip/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp): 使用 JSON Schema 去校验 JSON 的命令行工具。 + * [schemavalidator](https://github.com/Tencent/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp): 使用 JSON Schema 去校验 JSON 的命令行工具。 * 进阶 - * [prettyauto](https://github.com/miloyip/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/miloyip/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,可自动处理任何 UTF 编码的 JSON。 - * [parsebyparts](https://github.com/miloyip/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例子中的 `AsyncDocumentParser` 类使用 C++ 线程来逐段解析 JSON。 - * [filterkey](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 移取使用者指定的键值的命令行工具。 - * [filterkeydom](https://github.com/miloyip/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生成器(generator)去填充一个 `Document`。 \ No newline at end of file + * [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) 的修改版本,可自动处理任何 UTF 编码的 JSON。 + * [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): 这例子中的 `AsyncDocumentParser` 类使用 C++ 线程来逐段解析 JSON。 + * [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): 移取使用者指定的键值的命令行工具。 + * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): 如上的工具,但展示如何使用生成器(generator)去填充一个 `Document`。 \ No newline at end of file diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp index eed6fba..d5a688d 100644 --- a/test/unittest/pointertest.cpp +++ b/test/unittest/pointertest.cpp @@ -1488,7 +1488,7 @@ TEST(Pointer, Ambiguity) { } } -// https://github.com/miloyip/rapidjson/issues/483 +// https://github.com/Tencent/rapidjson/issues/483 namespace myjson { class MyAllocator diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index dad33d6..e530801 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -233,7 +233,7 @@ static void TestParseDouble() { TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) - TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120 + TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/Tencent/rapidjson/issues/120 TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0); TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ diff --git a/travis-doxygen.sh b/travis-doxygen.sh index e5c0320..33ec6ab 100755 --- a/travis-doxygen.sh +++ b/travis-doxygen.sh @@ -8,7 +8,7 @@ DOXYGEN_VER=doxygen-1.8.13 DOXYGEN_TAR=${DOXYGEN_VER}.linux.bin.tar.gz DOXYGEN_URL="http://ftp.stack.nl/pub/users/dimitri/${DOXYGEN_TAR}" -: ${GITHUB_REPO:="miloyip/rapidjson"} +: ${GITHUB_REPO:="Tencent/rapidjson"} GITHUB_HOST="github.com" GITHUB_CLONE="git://${GITHUB_HOST}/${GITHUB_REPO}" GITHUB_URL="https://${GITHUB_HOST}/${GITHUB_PUSH-${GITHUB_REPO}}" From 4c0f0036b54776dfc48ad76eca685caea0a1dc82 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Thu, 14 Sep 2017 11:55:31 +0800 Subject: [PATCH 051/128] Update appveyor badge and link --- readme.md | 4 ++-- readme.zh-cn.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index c9e9b1a..be22e20 100644 --- a/readme.md +++ b/readme.md @@ -22,8 +22,8 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights [lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status" [lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status" -[win-badge]: https://ci.appveyor.com/api/projects/status/github/Tencent/rapidjson?branch=master&svg=true "AppVeyor build status" -[win-link]: https://ci.appveyor.com/project/Tencent/rapidjson/branch/master "AppVeyor build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/l6qulgqahcayidrf/branch/master?svg=true "AppVeyor build status" +[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson-0fdqj/branch/master "AppVeyor build status" [cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage" [cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage" diff --git a/readme.zh-cn.md b/readme.zh-cn.md index 422667b..bca8897 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -22,8 +22,8 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights [lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status" [lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status" -[win-badge]: https://ci.appveyor.com/api/projects/status/github/Tencent/rapidjson?branch=master&svg=true "AppVeyor build status" -[win-link]: https://ci.appveyor.com/project/Tencent/rapidjson/branch/master "AppVeyor build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/l6qulgqahcayidrf/branch/master?svg=true "AppVeyor build status" +[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson-0fdqj/branch/master "AppVeyor build status" [cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage" [cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage" From 379b337444c5993a5bebf941f22d0fca236db8cf Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Sat, 16 Sep 2017 16:32:37 +0700 Subject: [PATCH 052/128] Add failing test for the case when a remote schema is violated (#1064) --- test/unittest/schematest.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 9b99ba8..6c395d1 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -124,14 +124,20 @@ TEST(SchemaValidator, Hasher) { #define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer) \ {\ - SchemaValidator validator(schema);\ + INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, SchemaValidator, Pointer) \ +} + +#define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer,\ + SchemaValidatorType, PointerType) \ +{\ + SchemaValidatorType validator(schema);\ Document d;\ /*printf("\n%s\n", json);*/\ d.Parse(json);\ EXPECT_FALSE(d.HasParseError());\ EXPECT_FALSE(d.Accept(validator));\ EXPECT_FALSE(validator.IsValid());\ - if (validator.GetInvalidSchemaPointer() != Pointer(invalidSchemaPointer)) {\ + if (validator.GetInvalidSchemaPointer() != PointerType(invalidSchemaPointer)) {\ StringBuffer sb;\ validator.GetInvalidSchemaPointer().Stringify(sb);\ printf("GetInvalidSchemaPointer() Expected: %s Actual: %s\n", invalidSchemaPointer, sb.GetString());\ @@ -142,7 +148,7 @@ TEST(SchemaValidator, Hasher) { printf("GetInvalidSchemaKeyword() Expected: %s Actual %s\n", invalidSchemaKeyword, validator.GetInvalidSchemaKeyword());\ ADD_FAILURE();\ }\ - if (validator.GetInvalidDocumentPointer() != Pointer(invalidDocumentPointer)) {\ + if (validator.GetInvalidDocumentPointer() != PointerType(invalidDocumentPointer)) {\ StringBuffer sb;\ validator.GetInvalidDocumentPointer().Stringify(sb);\ printf("GetInvalidDocumentPointer() Expected: %s Actual: %s\n", invalidDocumentPointer, sb.GetString());\ @@ -1348,6 +1354,17 @@ TEST(SchemaValidator, Issue1017_allOfHandler) { EXPECT_STREQ("{\"cyanArray2\":[],\"blackArray\":[]}", sb.GetString()); } +TEST(SchemaValidator, Ref_remote) { + typedef GenericSchemaDocument > SchemaDocumentType; + RemoteSchemaDocumentProvider provider; + Document sd; + sd.Parse("{\"$ref\": \"http://localhost:1234/subSchemas.json#/integer\"}"); + SchemaDocumentType s(sd, &provider); + typedef GenericSchemaValidator >, MemoryPoolAllocator<> > SchemaValidatorType; + typedef GenericPointer > PointerType; + INVALIDATE_(s, "null", "/integer", "type", "", SchemaValidatorType, PointerType); +} + #ifdef __clang__ RAPIDJSON_DIAG_POP #endif From 2bfd0cc6c7f1f2ad2c2b142ec64906ba6c8a551c Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Sat, 23 Sep 2017 20:42:39 +0700 Subject: [PATCH 053/128] internal::Schema: Keep pointer for future use --- include/rapidjson/schema.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index abcf1a1..e51b369 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -349,6 +349,7 @@ public: Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : allocator_(allocator), + pointer_(p), typeless_(schemaDocument->GetTypeless()), enum_(), enumCount_(), @@ -596,6 +597,10 @@ public: #endif } + const PointerType& GetPointer() const { + return pointer_; + } + bool BeginValue(Context& context) const { if (context.inArray) { if (uniqueItems_) @@ -1215,6 +1220,7 @@ private: }; AllocatorType* allocator_; + PointerType pointer_; const SchemaType* typeless_; uint64_t* enum_; SizeType enumCount_; @@ -1650,7 +1656,7 @@ public: //! Gets the JSON pointer pointed to the invalid schema. PointerType GetInvalidSchemaPointer() const { - return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema()); + return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); } //! Gets the keyword of invalid schema. From c2371584a0550f43a959140efe3cd83b8c6ede63 Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Sat, 16 Sep 2017 17:48:54 +0700 Subject: [PATCH 054/128] Keep schema URI in GenericSchemaDocument and internal::Schema --- include/rapidjson/schema.h | 23 ++++++++++++++++++++--- test/unittest/schematest.cpp | 21 ++++++++++----------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index e51b369..5a81854 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -349,6 +349,7 @@ public: Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : allocator_(allocator), + uri_(schemaDocument->GetURI(), *allocator), pointer_(p), typeless_(schemaDocument->GetTypeless()), enum_(), @@ -597,6 +598,10 @@ public: #endif } + const SValue& GetURI() const { + return uri_; + } + const PointerType& GetPointer() const { return pointer_; } @@ -1220,6 +1225,7 @@ private: }; AllocatorType* allocator_; + SValue uri_; PointerType pointer_; const SchemaType* typeless_; uint64_t* enum_; @@ -1330,6 +1336,7 @@ public: typedef typename EncodingType::Ch Ch; typedef internal::Schema SchemaType; typedef GenericPointer PointerType; + typedef GenericValue URIType; friend class internal::Schema; template friend class GenericSchemaValidator; @@ -1339,10 +1346,13 @@ public: Compile a JSON document into schema document. \param document A JSON document as source. + \param uri The base URI of this schema document for purposes of violation reporting. + \param uriLength Length of \c name, in code points. \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. \param allocator An optional allocator instance for allocating memory. Can be null. */ - explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : + explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, + IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : remoteProvider_(remoteProvider), allocator_(allocator), ownAllocator_(), @@ -1354,8 +1364,11 @@ public: if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + Ch noUri[1] = {0}; + uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); + typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); - new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_); // Generate root schema, it will call CreateSchema() to create sub-schemas, // And call AddRefSchema() if there are $ref. @@ -1393,7 +1406,8 @@ public: root_(rhs.root_), typeless_(rhs.typeless_), schemaMap_(std::move(rhs.schemaMap_)), - schemaRef_(std::move(rhs.schemaRef_)) + schemaRef_(std::move(rhs.schemaRef_)), + uri_(std::move(rhs.uri_)) { rhs.remoteProvider_ = 0; rhs.allocator_ = 0; @@ -1415,6 +1429,8 @@ public: RAPIDJSON_DELETE(ownAllocator_); } + const URIType& GetURI() const { return uri_; } + //! Get the root schema. const SchemaType& GetRoot() const { return *root_; } @@ -1545,6 +1561,7 @@ private: SchemaType* typeless_; internal::Stack schemaMap_; // Stores created Pointer -> Schemas internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref + URIType uri_; }; //! GenericSchemaDocument using Value type. diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 6c395d1..34436ac 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -1071,6 +1071,12 @@ public: "jsonschema/remotes/folder/folderInteger.json", "draft-04/schema" }; + const char* uris[kCount] = { + "http://localhost:1234/integer.json", + "http://localhost:1234/subSchemas.json", + "http://localhost:1234/folder/folderInteger.json", + "http://json-schema.org/draft-04/schema" + }; for (size_t i = 0; i < kCount; i++) { sd_[i] = 0; @@ -1087,7 +1093,7 @@ public: MemoryPoolAllocator<> stackAllocator(stackBuffer, sizeof(stackBuffer)); DocumentType d(&documentAllocator_, 1024, &stackAllocator); d.Parse(json); - sd_[i] = new SchemaDocumentType(d, 0, &schemaAllocator_); + sd_[i] = new SchemaDocumentType(d, uris[i], static_cast(strlen(uris[i])), 0, &schemaAllocator_); MemoryPoolAllocator<>::Free(json); } }; @@ -1099,15 +1105,8 @@ public: } virtual const SchemaDocumentType* GetRemoteDocument(const char* uri, SizeType length) { - const char* uris[kCount] = { - "http://localhost:1234/integer.json", - "http://localhost:1234/subSchemas.json", - "http://localhost:1234/folder/folderInteger.json", - "http://json-schema.org/draft-04/schema" - }; - for (size_t i = 0; i < kCount; i++) - if (strncmp(uri, uris[i], length) == 0 && strlen(uris[i]) == length) + if (typename SchemaDocumentType::URIType(uri, length) == sd_[i]->GetURI()) return sd_[i]; return 0; } @@ -1196,7 +1195,7 @@ TEST(SchemaValidator, TestSuite) { else { for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) { { - SchemaDocumentType schema((*schemaItr)["schema"], &provider, &schemaAllocator); + SchemaDocumentType schema((*schemaItr)["schema"], filenames[i], static_cast(strlen(filenames[i])), &provider, &schemaAllocator); GenericSchemaValidator >, MemoryPoolAllocator<> > validator(schema, &validatorAllocator); const char* description1 = (*schemaItr)["description"].GetString(); const Value& tests = (*schemaItr)["tests"]; @@ -1359,7 +1358,7 @@ TEST(SchemaValidator, Ref_remote) { RemoteSchemaDocumentProvider provider; Document sd; sd.Parse("{\"$ref\": \"http://localhost:1234/subSchemas.json#/integer\"}"); - SchemaDocumentType s(sd, &provider); + SchemaDocumentType s(sd, 0, 0, &provider); typedef GenericSchemaValidator >, MemoryPoolAllocator<> > SchemaValidatorType; typedef GenericPointer > PointerType; INVALIDATE_(s, "null", "/integer", "type", "", SchemaValidatorType, PointerType); From f716c3bfb53d22ef7fab6fb07fcb869ccf19b014 Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Sat, 16 Sep 2017 21:39:22 +0700 Subject: [PATCH 055/128] Report schema violation details (#619) --- include/rapidjson/schema.h | 661 ++++++++++++++++++++++++++++++------- 1 file changed, 547 insertions(+), 114 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 5a81854..53062eb 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -17,6 +17,7 @@ #include "document.h" #include "pointer.h" +#include "stringbuffer.h" #include // abs, floor #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) @@ -157,6 +158,62 @@ public: virtual void FreeState(void* p) = 0; }; +/////////////////////////////////////////////////////////////////////////////// +// IValidationErrorHandler + +template +class IValidationErrorHandler { +public: + typedef typename SchemaType::Ch Ch; + typedef typename SchemaType::SValue SValue; + + virtual ~IValidationErrorHandler() {} + + virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0; + virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0; + virtual void NotMultipleOf(double actual, const SValue& expected) = 0; + virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0; + virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0; + + virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0; + virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0; + virtual void DoesNotMatch(const Ch* str, SizeType length) = 0; + + virtual void DisallowedItem(SizeType index) = 0; + virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0; + virtual void DuplicateItems(SizeType index1, SizeType index2) = 0; + + virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0; + virtual void StartMissingProperties() = 0; + virtual void AddMissingProperty(const SValue& name) = 0; + virtual bool EndMissingProperties() = 0; + virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void DisallowedProperty(const Ch* name, SizeType length) = 0; + + virtual void StartDependencyErrors() = 0; + virtual void StartMissingDependentProperties() = 0; + virtual void AddMissingDependentProperty(const SValue& targetName) = 0; + virtual void EndMissingDependentProperties(const SValue& sourceName) = 0; + virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0; + virtual bool EndDependencyErrors() = 0; + + virtual void DisallowedValue() = 0; + virtual void StartDisallowedType() = 0; + virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0; + virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0; + virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0; + virtual void Disallowed() = 0; +}; + + /////////////////////////////////////////////////////////////////////////////// // Hasher @@ -345,6 +402,7 @@ public: typedef SchemaValidationContext Context; typedef Schema SchemaType; typedef GenericValue SValue; + typedef IValidationErrorHandler ErrorHandler; friend class GenericSchemaDocument; Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : @@ -606,7 +664,7 @@ public: return pointer_; } - bool BeginValue(Context& context) const { + bool BeginValue(Context& context, ErrorHandler& eh) const { if (context.inArray) { if (uniqueItems_) context.valueUniqueness = true; @@ -620,8 +678,10 @@ public: context.valueSchema = additionalItemsSchema_; else if (additionalItems_) context.valueSchema = typeless_; - else + else { + eh.DisallowedItem(context.arrayElementIndex); RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); + } } else context.valueSchema = typeless_; @@ -631,7 +691,7 @@ public: return true; } - RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + RAPIDJSON_FORCEINLINE bool EndValue(Context& context, ErrorHandler& eh) const { if (context.patternPropertiesValidatorCount > 0) { bool otherValid = false; SizeType count = context.patternPropertiesValidatorCount; @@ -646,15 +706,21 @@ public: } if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { - if (!patternValid) + if (!patternValid) { + eh.PropertyViolations(context.patternPropertiesValidators, count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } } else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { - if (!patternValid || !otherValid) + if (!patternValid || !otherValid) { + eh.PropertyViolations(context.patternPropertiesValidators, count + 1); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } } - else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) + else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) + eh.PropertyViolations(context.patternPropertiesValidators, count + 1); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } } if (enum_) { @@ -662,19 +728,23 @@ public: for (SizeType i = 0; i < enumCount_; i++) if (enum_[i] == h) goto foundEnum; + eh.DisallowedValue(); RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); foundEnum:; } if (allOf_.schemas) for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) - if (!context.validators[i]->IsValid()) + if (!context.validators[i]->IsValid()) { + eh.NotAllOf(&context.validators[allOf_.begin], allOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); + } if (anyOf_.schemas) { for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) if (context.validators[i]->IsValid()) goto foundAny; + eh.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); foundAny:; } @@ -683,96 +753,117 @@ public: bool oneValid = false; for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) if (context.validators[i]->IsValid()) { - if (oneValid) + if (oneValid) { + eh.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); - else + } else oneValid = true; } - if (!oneValid) + if (!oneValid) { + eh.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } } - if (not_ && context.validators[notValidatorIndex_]->IsValid()) + if (not_ && context.validators[notValidatorIndex_]->IsValid()) { + eh.Disallowed(); RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); + } return true; } - bool Null(Context& context) const { - if (!(type_ & (1 << kNullSchemaType))) + bool Null(Context& context, ErrorHandler& eh) const { + if (!(type_ & (1 << kNullSchemaType))) { + DisallowedType(eh, GetNullString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } return CreateParallelValidator(context); } - bool Bool(Context& context, bool) const { - if (!(type_ & (1 << kBooleanSchemaType))) + bool Bool(Context& context, ErrorHandler& eh, bool) const { + if (!(type_ & (1 << kBooleanSchemaType))) { + DisallowedType(eh, GetBooleanString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } return CreateParallelValidator(context); } - bool Int(Context& context, int i) const { - if (!CheckInt(context, i)) + bool Int(Context& context, ErrorHandler& eh, int i) const { + if (!CheckInt(context, eh, i)) return false; return CreateParallelValidator(context); } - bool Uint(Context& context, unsigned u) const { - if (!CheckUint(context, u)) + bool Uint(Context& context, ErrorHandler& eh, unsigned u) const { + if (!CheckUint(context, eh, u)) return false; return CreateParallelValidator(context); } - bool Int64(Context& context, int64_t i) const { - if (!CheckInt(context, i)) + bool Int64(Context& context, ErrorHandler& eh, int64_t i) const { + if (!CheckInt(context, eh, i)) return false; return CreateParallelValidator(context); } - bool Uint64(Context& context, uint64_t u) const { - if (!CheckUint(context, u)) + bool Uint64(Context& context, ErrorHandler& eh, uint64_t u) const { + if (!CheckUint(context, eh, u)) return false; return CreateParallelValidator(context); } - bool Double(Context& context, double d) const { - if (!(type_ & (1 << kNumberSchemaType))) + bool Double(Context& context, ErrorHandler& eh, double d) const { + if (!(type_ & (1 << kNumberSchemaType))) { + DisallowedType(eh, GetNumberString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } - if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) + if (!minimum_.IsNull() && !CheckDoubleMinimum(context, eh, d)) return false; - if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) + if (!maximum_.IsNull() && !CheckDoubleMaximum(context, eh, d)) return false; - if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, eh, d)) return false; return CreateParallelValidator(context); } - bool String(Context& context, const Ch* str, SizeType length, bool) const { - if (!(type_ & (1 << kStringSchemaType))) + bool String(Context& context, ErrorHandler& eh, const Ch* str, SizeType length, bool) const { + if (!(type_ & (1 << kStringSchemaType))) { + DisallowedType(eh, GetStringString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } if (minLength_ != 0 || maxLength_ != SizeType(~0)) { SizeType count; if (internal::CountStringCodePoint(str, length, &count)) { - if (count < minLength_) + if (count < minLength_) { + eh.TooShort(str, length, minLength_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); - if (count > maxLength_) + } + if (count > maxLength_) { + eh.TooLong(str, length, maxLength_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); + } } } - if (pattern_ && !IsPatternMatch(pattern_, str, length)) + if (pattern_ && !IsPatternMatch(pattern_, str, length)) { + eh.DoesNotMatch(str, length); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); + } return CreateParallelValidator(context); } - bool StartObject(Context& context) const { - if (!(type_ & (1 << kObjectSchemaType))) + bool StartObject(Context& context, ErrorHandler& eh) const { + if (!(type_ & (1 << kObjectSchemaType))) { + DisallowedType(eh, GetObjectString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } if (hasDependencies_ || hasRequired_) { context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); @@ -789,7 +880,7 @@ public: return CreateParallelValidator(context); } - bool Key(Context& context, const Ch* str, SizeType len, bool) const { + bool Key(Context& context, ErrorHandler& eh, const Ch* str, SizeType len, bool) const { if (patternProperties_) { context.patternPropertiesSchemaCount = 0; for (SizeType i = 0; i < patternPropertyCount_; i++) @@ -830,45 +921,65 @@ public: return true; } - if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties + if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties + eh.DisallowedProperty(str, len); RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); - - return true; - } - - bool EndObject(Context& context, SizeType memberCount) const { - if (hasRequired_) - for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].required) - if (!context.propertyExist[index]) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); - - if (memberCount < minProperties_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); - - if (memberCount > maxProperties_) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); - - if (hasDependencies_) { - for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) - if (context.propertyExist[sourceIndex]) { - if (properties_[sourceIndex].dependencies) { - for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) - if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); - } - else if (properties_[sourceIndex].dependenciesSchema) - if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); - } } return true; } - bool StartArray(Context& context) const { - if (!(type_ & (1 << kArraySchemaType))) + bool EndObject(Context& context, ErrorHandler& eh, SizeType memberCount) const { + if (hasRequired_) { + eh.StartMissingProperties(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].required && !context.propertyExist[index]) + eh.AddMissingProperty(properties_[index].name); + if (eh.EndMissingProperties()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + } + + if (memberCount < minProperties_) { + eh.TooFewProperties(memberCount, minProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); + } + + if (memberCount > maxProperties_) { + eh.TooManyProperties(memberCount, maxProperties_); + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); + } + + if (hasDependencies_) { + eh.StartDependencyErrors(); + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { + const Property& source = properties_[sourceIndex]; + if (context.propertyExist[sourceIndex]) { + if (source.dependencies) { + eh.StartMissingDependentProperties(); + for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) + if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) + eh.AddMissingDependentProperty(properties_[targetIndex].name); + eh.EndMissingDependentProperties(source.name); + } + else if (source.dependenciesSchema) { + ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex]; + if (!dependenciesValidator->IsValid()) + eh.AddDependencySchemaError(source.name, dependenciesValidator); + } + } + } + if (eh.EndDependencyErrors()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + } + + return true; + } + + bool StartArray(Context& context, ErrorHandler& eh) const { + if (!(type_ & (1 << kArraySchemaType))) { + DisallowedType(eh, GetArrayString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } context.arrayElementIndex = 0; context.inArray = true; @@ -876,14 +987,18 @@ public: return CreateParallelValidator(context); } - bool EndArray(Context& context, SizeType elementCount) const { + bool EndArray(Context& context, ErrorHandler& eh, SizeType elementCount) const { context.inArray = false; - if (elementCount < minItems_) + if (elementCount < minItems_) { + eh.TooFewItems(elementCount, minItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); + } - if (elementCount > maxItems_) + if (elementCount > maxItems_) { + eh.TooManyItems(elementCount, maxItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); + } return true; } @@ -1103,104 +1218,144 @@ private: return false; } - bool CheckInt(Context& context, int64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + bool CheckInt(Context& context, ErrorHandler& eh, int64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(eh, GetIntegerString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } if (!minimum_.IsNull()) { if (minimum_.IsInt64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) + if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) { + eh.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } } else if (minimum_.IsUint64()) { + eh.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() } - else if (!CheckDoubleMinimum(context, static_cast(i))) + else if (!CheckDoubleMinimum(context, eh, static_cast(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsInt64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { + eh.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } } else if (maximum_.IsUint64()) { } /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() - else if (!CheckDoubleMaximum(context, static_cast(i))) + else if (!CheckDoubleMaximum(context, eh, static_cast(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { - if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) + if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) { + eh.NotMultipleOf(i, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) + else if (!CheckDoubleMultipleOf(context, eh, static_cast(i))) return false; } return true; } - bool CheckUint(Context& context, uint64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + bool CheckUint(Context& context, ErrorHandler& eh, uint64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(eh, GetIntegerString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } if (!minimum_.IsNull()) { if (minimum_.IsUint64()) { - if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) + if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) { + eh.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } } else if (minimum_.IsInt64()) /* do nothing */; // i >= 0 > minimum.Getint64() - else if (!CheckDoubleMinimum(context, static_cast(i))) + else if (!CheckDoubleMinimum(context, eh, static_cast(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsUint64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { + eh.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } } - else if (maximum_.IsInt64()) + else if (maximum_.IsInt64()) { + eh.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ - else if (!CheckDoubleMaximum(context, static_cast(i))) + } + else if (!CheckDoubleMaximum(context, eh, static_cast(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { - if (i % multipleOf_.GetUint64() != 0) + if (i % multipleOf_.GetUint64() != 0) { + eh.NotMultipleOf(i, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } } - else if (!CheckDoubleMultipleOf(context, static_cast(i))) + else if (!CheckDoubleMultipleOf(context, eh, static_cast(i))) return false; } return true; } - bool CheckDoubleMinimum(Context& context, double d) const { - if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) + bool CheckDoubleMinimum(Context& context, ErrorHandler& eh, double d) const { + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { + eh.BelowMinimum(d, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } return true; } - bool CheckDoubleMaximum(Context& context, double d) const { - if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) + bool CheckDoubleMaximum(Context& context, ErrorHandler& eh, double d) const { + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { + eh.AboveMaximum(d, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } return true; } - bool CheckDoubleMultipleOf(Context& context, double d) const { + bool CheckDoubleMultipleOf(Context& context, ErrorHandler& eh, double d) const { double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); double q = std::floor(a / b); double r = a - q * b; - if (r > 0.0) + if (r > 0.0) { + eh.NotMultipleOf(d, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } return true; } + void DisallowedType(ErrorHandler& eh, const ValueType& actualType) const { + eh.StartDisallowedType(); + + if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString()); + if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString()); + if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString()); + if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString()); + if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString()); + + if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString()); + else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString()); + + eh.EndDisallowedType(actualType); + } + struct Property { Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} ~Property() { AllocatorType::Free(dependencies); } @@ -1590,13 +1745,17 @@ template < typename StateAllocator = CrtAllocator> class GenericSchemaValidator : public internal::ISchemaStateFactory, - public internal::ISchemaValidator + public internal::ISchemaValidator, + public internal::IValidationErrorHandler { public: typedef typename SchemaDocumentType::SchemaType SchemaType; typedef typename SchemaDocumentType::PointerType PointerType; typedef typename SchemaType::EncodingType EncodingType; + typedef typename SchemaType::SValue SValue; typedef typename EncodingType::Ch Ch; + typedef GenericStringRef StringRefType; + typedef GenericValue ValueType; //! Constructor without output handler. /*! @@ -1618,6 +1777,9 @@ public: schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) @@ -1646,6 +1808,9 @@ public: schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(&outputHandler), + error_(kObjectType), + currentError_(), + missingDependents_(), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) @@ -1664,6 +1829,9 @@ public: while (!schemaStack_.Empty()) PopSchema(); documentStack_.Clear(); + error_.SetObject(); + currentError_.SetNull(); + missingDependents_.SetNull(); valid_ = true; } @@ -1671,6 +1839,10 @@ public: // Implementation of ISchemaValidator virtual bool IsValid() const { return valid_; } + //! Gets the error object. + ValueType& GetError() { return error_; } + const ValueType& GetError() const { return error_; } + //! Gets the JSON pointer pointed to the invalid schema. PointerType GetInvalidSchemaPointer() const { return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); @@ -1686,6 +1858,186 @@ public: return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); } + void NotMultipleOf(int64_t actual, const SValue& expected) { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void NotMultipleOf(uint64_t actual, const SValue& expected) { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void NotMultipleOf(double actual, const SValue& expected) { + AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected); + } + void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void AboveMaximum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMaximumString : 0); + } + void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + void BelowMinimum(double actual, const SValue& expected, bool exclusive) { + AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected, + exclusive ? &SchemaType::GetExclusiveMinimumString : 0); + } + + void TooLong(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(SchemaType::GetMaxLengthString(), + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void TooShort(const Ch* str, SizeType length, SizeType expected) { + AddNumberError(SchemaType::GetMinLengthString(), + ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move()); + } + void DoesNotMatch(const Ch* str, SizeType length) { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetPatternString()); + } + + void DisallowedItem(SizeType index) { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetAdditionalItemsString(), true); + } + void TooFewItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMinItemsString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooManyItems(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMaxItemsString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void DuplicateItems(SizeType index1, SizeType index2) { + ValueType duplicates(kArrayType); + duplicates.PushBack(index1, GetStateAllocator()); + duplicates.PushBack(index2, GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator()); + AddCurrentError(SchemaType::GetUniqueItemsString(), true); + } + + void TooManyProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMaxPropertiesString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void TooFewProperties(SizeType actualCount, SizeType expectedCount) { + AddNumberError(SchemaType::GetMinPropertiesString(), + ValueType(actualCount).Move(), SValue(expectedCount).Move()); + } + void StartMissingProperties() { + currentError_.SetArray(); + } + void AddMissingProperty(const SValue& name) { + currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator()); + } + bool EndMissingProperties() { + if (currentError_.Empty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetMissingString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetRequiredString()); + return true; + } + void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) { + for (SizeType i = 0; i < count; ++i) + MergeError(static_cast(subvalidators[i])->GetError()); + } + void DisallowedProperty(const Ch* name, SizeType length) { + currentError_.SetObject(); + currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator()); + AddCurrentError(SchemaType::GetAdditionalPropertiesString(), true); + } + + void StartDependencyErrors() { + currentError_.SetObject(); + } + void StartMissingDependentProperties() { + missingDependents_.SetArray(); + } + void AddMissingDependentProperty(const SValue& targetName) { + missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndMissingDependentProperties(const SValue& sourceName) { + if (!missingDependents_.Empty()) + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), + missingDependents_, GetStateAllocator()); + } + void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) { + currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), + static_cast(subvalidator)->GetError(), GetStateAllocator()); + } + bool EndDependencyErrors() { + if (currentError_.ObjectEmpty()) + return false; + ValueType error(kObjectType); + error.AddMember(GetErrorsString(), currentError_, GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetDependenciesString()); + return true; + } + + void DisallowedValue() { + currentError_.SetObject(); + AddCurrentError(SchemaType::GetEnumString()); + } + void StartDisallowedType() { + currentError_.SetArray(); + } + void AddExpectedType(const typename SchemaType::ValueType& expectedType) { + currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator()); + } + void EndDisallowedType(const typename SchemaType::ValueType& actualType) { + ValueType error(kObjectType); + error.AddMember(GetExpectedString(), currentError_, GetStateAllocator()); + error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator()); + currentError_ = error; + AddCurrentError(SchemaType::GetTypeString()); + } + void NotAllOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(SchemaType::GetAllOfString(), subvalidators, count); + } + void NoneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count); + } + void NotOneOf(ISchemaValidator** subvalidators, SizeType count) { + AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count); + } + void Disallowed() { + currentError_.SetObject(); + AddCurrentError(SchemaType::GetNotString()); + } + +#define RAPIDJSON_STRING_(name, ...) \ + static const StringRefType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const StringRefType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1)); \ + return v;\ + } + + RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f') + RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f') + RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd') + RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l') + RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd') + RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g') + RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's') + RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's') + +#undef RAPIDJSON_STRING_ + #if RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ RAPIDJSON_MULTILINEMACRO_BEGIN\ @@ -1724,20 +2076,20 @@ RAPIDJSON_MULTILINEMACRO_END RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) - bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } - bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } - bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } - bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } - bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } - bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } - bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } + bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext(), *this), ( )); } + bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), *this, b), (b)); } + bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), *this, i), (i)); } + bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), *this, u), (u)); } + bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), *this, i), (i)); } + bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), *this, u), (u)); } + bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), *this, d), (d)); } bool RawNumber(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), *this, str, length, copy), (str, length, copy)); } bool String(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), *this, str, length, copy), (str, length, copy)); } bool StartObject() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext(), *this)); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); return valid_ = !outputHandler_ || outputHandler_->StartObject(); } @@ -1745,7 +2097,7 @@ RAPIDJSON_MULTILINEMACRO_END bool Key(const Ch* str, SizeType len, bool copy) { if (!valid_) return false; AppendToken(str, len); - if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; + if (!CurrentSchema().Key(CurrentContext(), *this, str, len, copy)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); } @@ -1753,12 +2105,12 @@ RAPIDJSON_MULTILINEMACRO_END bool EndObject(SizeType memberCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); - if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; + if (!CurrentSchema().EndObject(CurrentContext(), *this, memberCount)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); } bool StartArray() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext(), *this)); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); return valid_ = !outputHandler_ || outputHandler_->StartArray(); } @@ -1766,7 +2118,7 @@ RAPIDJSON_MULTILINEMACRO_END bool EndArray(SizeType elementCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); - if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; + if (!CurrentSchema().EndArray(CurrentContext(), *this, elementCount)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); } @@ -1777,7 +2129,7 @@ RAPIDJSON_MULTILINEMACRO_END // Implementation of ISchemaStateFactory virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { - return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, + return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom(), documentStack_.GetSize(), #if RAPIDJSON_SCHEMA_VERBOSE depth_ + 1, #endif @@ -1820,6 +2172,7 @@ private: GenericSchemaValidator( const SchemaDocumentType& schemaDocument, const SchemaType& root, + const char* basePath, size_t basePathSize, #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth, #endif @@ -1834,11 +2187,16 @@ private: schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(depth) #endif { + if (basePath && basePathSize) + memcpy(documentStack_.template Push(basePathSize), basePath, basePathSize); } StateAllocator& GetStateAllocator() { @@ -1854,7 +2212,7 @@ private: if (CurrentContext().inArray) internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); - if (!CurrentSchema().BeginValue(CurrentContext())) + if (!CurrentSchema().BeginValue(CurrentContext(), *this)) return false; SizeType count = CurrentContext().patternPropertiesSchemaCount; @@ -1879,7 +2237,7 @@ private: } bool EndValue() { - if (!CurrentSchema().EndValue(CurrentContext())) + if (!CurrentSchema().EndValue(CurrentContext(), *this)) return false; #if RAPIDJSON_SCHEMA_VERBOSE @@ -1902,8 +2260,10 @@ private: if (!a) CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) - if (itr->GetUint64() == h) + if (itr->GetUint64() == h) { + DuplicateItems(static_cast(itr - a->Begin()), a->Size()); RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); + } a->PushBack(h, GetStateAllocator()); } } @@ -1943,6 +2303,70 @@ private: c->~Context(); } + void AddErrorLocation(ValueType& result, bool parent) { + GenericStringBuffer sb; + PointerType instancePointer = GetInvalidDocumentPointer(); + ((parent && instancePointer.GetTokenCount() > 0) + ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1) + : instancePointer).StringifyUriFragment(sb); + ValueType instanceRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator()); + sb.Clear(); + memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()), + CurrentSchema().GetURI().GetString(), + CurrentSchema().GetURI().GetStringLength() * sizeof(Ch)); + GetInvalidSchemaPointer().StringifyUriFragment(sb); + ValueType schemaRef(sb.GetString(), static_cast(sb.GetSize() / sizeof(Ch)), + GetStateAllocator()); + result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator()); + } + + void AddError(ValueType& keyword, ValueType& error) { + typename ValueType::MemberIterator member = error_.FindMember(keyword); + if (member == error_.MemberEnd()) + error_.AddMember(keyword, error, GetStateAllocator()); + else { + if (member->value.IsObject()) { + ValueType errors(kArrayType); + errors.PushBack(member->value, GetStateAllocator()); + member->value = errors; + } + member->value.PushBack(error, GetStateAllocator()); + } + } + + void AddCurrentError(const typename SchemaType::ValueType& keyword, bool parent = false) { + AddErrorLocation(currentError_, parent); + AddError(ValueType(keyword, GetStateAllocator(), false).Move(), currentError_); + } + + void MergeError(ValueType& other) { + for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) { + AddError(it->name, it->value); + } + } + + void AddNumberError(const typename SchemaType::ValueType& keyword, ValueType& actual, const SValue& expected, + const typename SchemaType::ValueType& (*exclusive)() = 0) { + currentError_.SetObject(); + currentError_.AddMember(GetActualString(), actual, GetStateAllocator()); + currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator()); + if (exclusive) + currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator()); + AddCurrentError(keyword); + } + + void AddErrorArray(const typename SchemaType::ValueType& keyword, + ISchemaValidator** subvalidators, SizeType count) { + ValueType errors(kArrayType); + for (SizeType i = 0; i < count; ++i) + errors.PushBack(static_cast(subvalidators[i])->GetError(), GetStateAllocator()); + currentError_.SetObject(); + currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator()); + AddCurrentError(keyword); + } + const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } Context& CurrentContext() { return *schemaStack_.template Top(); } const Context& CurrentContext() const { return *schemaStack_.template Top(); } @@ -1956,6 +2380,9 @@ private: 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) OutputHandler* outputHandler_; + ValueType error_; + ValueType currentError_; + ValueType missingDependents_; bool valid_; #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth_; @@ -1987,13 +2414,14 @@ class SchemaValidatingReader { public: typedef typename SchemaDocumentType::PointerType PointerType; typedef typename InputStream::Ch Ch; + typedef GenericValue ValueType; //! Constructor /*! \param is Input stream. \param sd Schema document. */ - SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {} + SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {} template bool operator()(Handler& handler) { @@ -2006,11 +2434,13 @@ public: invalidSchemaPointer_ = PointerType(); invalidSchemaKeyword_ = 0; invalidDocumentPointer_ = PointerType(); + error_.SetObject(); } else { invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); + error_.CopyFrom(validator.GetError(), allocator_); } return parseResult_; @@ -2021,6 +2451,7 @@ public: const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } + const ValueType& GetError() const { return error_; } private: InputStream& is_; @@ -2030,6 +2461,8 @@ private: PointerType invalidSchemaPointer_; const Ch* invalidSchemaKeyword_; PointerType invalidDocumentPointer_; + StackAllocator allocator_; + ValueType error_; bool isValid_; }; From 0566716802964da289a60fa252e77e767b433747 Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Mon, 18 Sep 2017 00:06:07 +0700 Subject: [PATCH 056/128] Extend schema validation tests to compare error object --- test/unittest/schematest.cpp | 954 ++++++++++++++++++++++++++++++----- 1 file changed, 825 insertions(+), 129 deletions(-) diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 34436ac..5bf39f8 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -119,15 +119,19 @@ TEST(SchemaValidator, Hasher) { sb.Clear();\ validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);\ printf("Invalid document: %s\n", sb.GetString());\ + sb.Clear();\ + Writer w(sb);\ + validator.GetError().Accept(w);\ + printf("Validation error: %s\n", sb.GetString());\ }\ } -#define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer) \ +#define INVALIDATE(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error) \ {\ - INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, SchemaValidator, Pointer) \ + INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, SchemaValidator, Pointer) \ } -#define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer,\ +#define INVALIDATE_(schema, json, invalidSchemaPointer, invalidSchemaKeyword, invalidDocumentPointer, error, \ SchemaValidatorType, PointerType) \ {\ SchemaValidatorType validator(schema);\ @@ -154,6 +158,15 @@ TEST(SchemaValidator, Hasher) { printf("GetInvalidDocumentPointer() Expected: %s Actual: %s\n", invalidDocumentPointer, sb.GetString());\ ADD_FAILURE();\ }\ + Document e;\ + e.Parse(error);\ + if (validator.GetError() != e) {\ + StringBuffer sb;\ + Writer w(sb);\ + validator.GetError().Accept(w);\ + printf("GetError() Expected: %s Actual: %s\n", error, sb.GetString());\ + ADD_FAILURE();\ + }\ } TEST(SchemaValidator, Typeless) { @@ -173,7 +186,11 @@ TEST(SchemaValidator, MultiType) { VALIDATE(s, "42", true); VALIDATE(s, "\"Life, the universe, and everything\"", true); - INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", ""); + INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"string\", \"number\"], \"actual\": \"array\"" + "}}"); } TEST(SchemaValidator, Enum_Typed) { @@ -182,7 +199,8 @@ TEST(SchemaValidator, Enum_Typed) { SchemaDocument s(sd); VALIDATE(s, "\"red\"", true); - INVALIDATE(s, "\"blue\"", "", "enum", ""); + INVALIDATE(s, "\"blue\"", "", "enum", "", + "{ \"enum\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}"); } TEST(SchemaValidator, Enum_Typless) { @@ -193,7 +211,8 @@ TEST(SchemaValidator, Enum_Typless) { VALIDATE(s, "\"red\"", true); VALIDATE(s, "null", true); VALIDATE(s, "42", true); - INVALIDATE(s, "0", "", "enum", ""); + INVALIDATE(s, "0", "", "enum", "", + "{ \"enum\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}"); } TEST(SchemaValidator, Enum_InvalidType) { @@ -202,7 +221,11 @@ TEST(SchemaValidator, Enum_InvalidType) { SchemaDocument s(sd); VALIDATE(s, "\"red\"", true); - INVALIDATE(s, "null", "", "type", ""); + INVALIDATE(s, "null", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"string\"], \"actual\": \"null\"" + "}}"); } TEST(SchemaValidator, AllOf) { @@ -212,7 +235,17 @@ TEST(SchemaValidator, AllOf) { SchemaDocument s(sd); VALIDATE(s, "\"ok\"", true); - INVALIDATE(s, "\"too long\"", "", "allOf", ""); + INVALIDATE(s, "\"too long\"", "", "allOf", "", + "{ \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": [" + " {}," + " { \"maxLength\": { " + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\", " + " \"expected\": 5, \"actual\": \"too long\"" + " }}" + " ]" + "}}"); } { Document sd; @@ -220,7 +253,16 @@ TEST(SchemaValidator, AllOf) { SchemaDocument s(sd); VALIDATE(s, "\"No way\"", false); - INVALIDATE(s, "-1", "", "allOf", ""); + INVALIDATE(s, "-1", "", "allOf", "", + "{ \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": [" + " { \"type\": { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + " }}," + " {}" + " ]" + "}}"); } } @@ -231,7 +273,20 @@ TEST(SchemaValidator, AnyOf) { VALIDATE(s, "\"Yes\"", true); VALIDATE(s, "42", true); - INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", ""); + INVALIDATE(s, "{ \"Not a\": \"string or number\" }", "", "anyOf", "", + "{ \"anyOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\", " + " \"errors\": [" + " { \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/0\"," + " \"expected\": [\"string\"], \"actual\": \"object\"" + " }}," + " { \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/anyOf/1\"," + " \"expected\": [\"number\"], \"actual\": \"object\"" + " }}" + " ]" + "}}"); } TEST(SchemaValidator, OneOf) { @@ -241,8 +296,22 @@ TEST(SchemaValidator, OneOf) { VALIDATE(s, "10", true); VALIDATE(s, "9", true); - INVALIDATE(s, "2", "", "oneOf", ""); - INVALIDATE(s, "15", "", "oneOf", ""); + INVALIDATE(s, "2", "", "oneOf", "", + "{ \"oneOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": [" + " { \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/0\"," + " \"expected\": 5, \"actual\": 2" + " }}," + " { \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/oneOf/1\"," + " \"expected\": 3, \"actual\": 2" + " }}" + " ]" + "}}"); + INVALIDATE(s, "15", "", "oneOf", "", + "{ \"oneOf\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\", \"errors\": [{}, {}]}}"); } TEST(SchemaValidator, Not) { @@ -252,7 +321,8 @@ TEST(SchemaValidator, Not) { VALIDATE(s, "42", true); VALIDATE(s, "{ \"key\": \"value\" }", true); - INVALIDATE(s, "\"I am a string\"", "", "not", ""); + INVALIDATE(s, "\"I am a string\"", "", "not", "", + "{ \"not\": { \"instanceRef\": \"#\", \"schemaRef\": \"#\" }}"); } TEST(SchemaValidator, Ref) { @@ -316,7 +386,17 @@ TEST(SchemaValidator, Ref_AllOf) { "}"); SchemaDocument s(sd); - INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address"); + INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address", + "{ \"allOf\": {" + " \"instanceRef\": \"#/shipping_address\"," + " \"schemaRef\": \"#/properties/shipping_address\"," + " \"errors\": [" + " {}," + " { \"required\": {" + " \"instanceRef\": \"#/shipping_address\"," + " \"schemaRef\": \"#/properties/shipping_address/allOf/1\"," + " \"missing\": [\"type\"]" + "}} ] }}"); VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true); } @@ -326,11 +406,31 @@ TEST(SchemaValidator, String) { SchemaDocument s(sd); VALIDATE(s, "\"I'm a string\"", true); - INVALIDATE(s, "42", "", "type", ""); - INVALIDATE(s, "2147483648", "", "type", ""); // 2^31 can only be fit in unsigned - INVALIDATE(s, "-2147483649", "", "type", ""); // -2^31 - 1 can only be fit in int64_t - INVALIDATE(s, "4294967296", "", "type", ""); // 2^32 can only be fit in int64_t - INVALIDATE(s, "3.1415926", "", "type", ""); + INVALIDATE(s, "42", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + "}}"); + INVALIDATE(s, "2147483648", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + "}}"); // 2^31 can only be fit in unsigned + INVALIDATE(s, "-2147483649", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + "}}"); // -2^31 - 1 can only be fit in int64_t + INVALIDATE(s, "4294967296", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + "}}"); // 2^32 can only be fit in int64_t + INVALIDATE(s, "3.1415926", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"string\"], \"actual\": \"number\"" + "}}"); } TEST(SchemaValidator, String_LengthRange) { @@ -338,10 +438,18 @@ TEST(SchemaValidator, String_LengthRange) { sd.Parse("{\"type\":\"string\",\"minLength\":2,\"maxLength\":3}"); SchemaDocument s(sd); - INVALIDATE(s, "\"A\"", "", "minLength", ""); + INVALIDATE(s, "\"A\"", "", "minLength", "", + "{ \"minLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 2, \"actual\": \"A\"" + "}}"); VALIDATE(s, "\"AB\"", true); VALIDATE(s, "\"ABC\"", true); - INVALIDATE(s, "\"ABCD\"", "", "maxLength", ""); + INVALIDATE(s, "\"ABCD\"", "", "maxLength", "", + "{ \"maxLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 3, \"actual\": \"ABCD\"" + "}}"); } #if RAPIDJSON_SCHEMA_HAS_REGEX @@ -352,8 +460,16 @@ TEST(SchemaValidator, String_Pattern) { VALIDATE(s, "\"555-1212\"", true); VALIDATE(s, "\"(888)555-1212\"", true); - INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", ""); - INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", ""); + INVALIDATE(s, "\"(888)555-1212 ext. 532\"", "", "pattern", "", + "{ \"pattern\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"actual\": \"(888)555-1212 ext. 532\"" + "}}"); + INVALIDATE(s, "\"(800)FLOWERS\"", "", "pattern", "", + "{ \"pattern\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"actual\": \"(800)FLOWERS\"" + "}}"); } TEST(SchemaValidator, String_Pattern_Invalid) { @@ -378,8 +494,16 @@ TEST(SchemaValidator, Integer) { VALIDATE(s, "-2147483649", true); // -2^31 - 1 can only be fit in int64_t VALIDATE(s, "2147483648", true); // 2^31 can only be fit in unsigned VALIDATE(s, "4294967296", true); // 2^32 can only be fit in int64_t - INVALIDATE(s, "3.1415926", "", "type", ""); - INVALIDATE(s, "\"42\"", "", "type", ""); + INVALIDATE(s, "3.1415926", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"integer\"], \"actual\": \"number\"" + "}}"); + INVALIDATE(s, "\"42\"", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"integer\"], \"actual\": \"string\"" + "}}"); } TEST(SchemaValidator, Integer_Range) { @@ -387,12 +511,24 @@ TEST(SchemaValidator, Integer_Range) { sd.Parse("{\"type\":\"integer\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}"); SchemaDocument s(sd); - INVALIDATE(s, "-1", "", "minimum", ""); + INVALIDATE(s, "-1", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 0, \"actual\": -1" + "}}"); VALIDATE(s, "0", true); VALIDATE(s, "10", true); VALIDATE(s, "99", true); - INVALIDATE(s, "100", "", "maximum", ""); - INVALIDATE(s, "101", "", "maximum", ""); + INVALIDATE(s, "100", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100" + "}}"); + INVALIDATE(s, "101", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101" + "}}"); } TEST(SchemaValidator, Integer_Range64Boundary) { @@ -400,7 +536,11 @@ TEST(SchemaValidator, Integer_Range64Boundary) { sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775807,\"maximum\":9223372036854775806}"); SchemaDocument s(sd); - INVALIDATE(s, "-9223372036854775808", "", "minimum", ""); + INVALIDATE(s, "-9223372036854775808", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -9223372036854775807, \"actual\": -9223372036854775808" + "}}"); VALIDATE(s, "-9223372036854775807", true); VALIDATE(s, "-2147483648", true); // int min VALIDATE(s, "0", true); @@ -408,8 +548,16 @@ TEST(SchemaValidator, Integer_Range64Boundary) { VALIDATE(s, "2147483648", true); // unsigned first VALIDATE(s, "4294967295", true); // unsigned max VALIDATE(s, "9223372036854775806", true); - INVALIDATE(s, "9223372036854775807", "", "maximum", ""); - INVALIDATE(s, "18446744073709551615", "", "maximum", ""); // uint64_t max + INVALIDATE(s, "9223372036854775807", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775806, \"actual\": 9223372036854775807" + "}}"); + INVALIDATE(s, "18446744073709551615", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775806, \"actual\": 18446744073709551615" + "}}"); // uint64_t max } TEST(SchemaValidator, Integer_RangeU64Boundary) { @@ -417,16 +565,48 @@ TEST(SchemaValidator, Integer_RangeU64Boundary) { sd.Parse("{\"type\":\"integer\",\"minimum\":9223372036854775808,\"maximum\":18446744073709551614}"); SchemaDocument s(sd); - INVALIDATE(s, "-9223372036854775808", "", "minimum", ""); - INVALIDATE(s, "9223372036854775807", "", "minimum", ""); - INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min - INVALIDATE(s, "0", "", "minimum", ""); - INVALIDATE(s, "2147483647", "", "minimum", ""); // int max - INVALIDATE(s, "2147483648", "", "minimum", ""); // unsigned first - INVALIDATE(s, "4294967295", "", "minimum", ""); // unsigned max + INVALIDATE(s, "-9223372036854775808", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808, \"actual\": -9223372036854775808" + "}}"); + INVALIDATE(s, "9223372036854775807", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808, \"actual\": 9223372036854775807" + "}}"); + INVALIDATE(s, "-2147483648", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808, \"actual\": -2147483648" + "}}"); // int min + INVALIDATE(s, "0", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808, \"actual\": 0" + "}}"); + INVALIDATE(s, "2147483647", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808, \"actual\": 2147483647" + "}}"); // int max + INVALIDATE(s, "2147483648", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808, \"actual\": 2147483648" + "}}"); // unsigned first + INVALIDATE(s, "4294967295", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808, \"actual\": 4294967295" + "}}"); // unsigned max VALIDATE(s, "9223372036854775808", true); VALIDATE(s, "18446744073709551614", true); - INVALIDATE(s, "18446744073709551615", "", "maximum", ""); + INVALIDATE(s, "18446744073709551615", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 18446744073709551614, \"actual\": 18446744073709551615" + "}}"); } TEST(SchemaValidator, Integer_Range64BoundaryExclusive) { @@ -434,10 +614,20 @@ TEST(SchemaValidator, Integer_Range64BoundaryExclusive) { sd.Parse("{\"type\":\"integer\",\"minimum\":-9223372036854775808,\"maximum\":18446744073709551615,\"exclusiveMinimum\":true,\"exclusiveMaximum\":true}"); SchemaDocument s(sd); - INVALIDATE(s, "-9223372036854775808", "", "minimum", ""); + INVALIDATE(s, "-9223372036854775808", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -9223372036854775808, \"exclusiveMinimum\": true, " + " \"actual\": -9223372036854775808" + "}}"); VALIDATE(s, "-9223372036854775807", true); VALIDATE(s, "18446744073709551614", true); - INVALIDATE(s, "18446744073709551615", "", "maximum", ""); + INVALIDATE(s, "18446744073709551615", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 18446744073709551615, \"exclusiveMaximum\": true, " + " \"actual\": 18446744073709551615" + "}}"); } TEST(SchemaValidator, Integer_MultipleOf) { @@ -449,8 +639,16 @@ TEST(SchemaValidator, Integer_MultipleOf) { VALIDATE(s, "10", true); VALIDATE(s, "-10", true); VALIDATE(s, "20", true); - INVALIDATE(s, "23", "", "multipleOf", ""); - INVALIDATE(s, "-23", "", "multipleOf", ""); + INVALIDATE(s, "23", "", "multipleOf", "", + "{ \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 10, \"actual\": 23" + "}}"); + INVALIDATE(s, "-23", "", "multipleOf", "", + "{ \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 10, \"actual\": -23" + "}}"); } TEST(SchemaValidator, Integer_MultipleOf64Boundary) { @@ -460,7 +658,11 @@ TEST(SchemaValidator, Integer_MultipleOf64Boundary) { VALIDATE(s, "0", true); VALIDATE(s, "18446744073709551615", true); - INVALIDATE(s, "18446744073709551614", "", "multipleOf", ""); + INVALIDATE(s, "18446744073709551614", "", "multipleOf", "", + "{ \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 18446744073709551615, \"actual\": 18446744073709551614" + "}}"); } TEST(SchemaValidator, Number_Range) { @@ -468,15 +670,31 @@ TEST(SchemaValidator, Number_Range) { sd.Parse("{\"type\":\"number\",\"minimum\":0,\"maximum\":100,\"exclusiveMaximum\":true}"); SchemaDocument s(sd); - INVALIDATE(s, "-1", "", "minimum", ""); + INVALIDATE(s, "-1", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 0, \"actual\": -1" + "}}"); VALIDATE(s, "0", true); VALIDATE(s, "0.1", true); VALIDATE(s, "10", true); VALIDATE(s, "99", true); VALIDATE(s, "99.9", true); - INVALIDATE(s, "100", "", "maximum", ""); - INVALIDATE(s, "100.0", "", "maximum", ""); - INVALIDATE(s, "101.5", "", "maximum", ""); + INVALIDATE(s, "100", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100" + "}}"); + INVALIDATE(s, "100.0", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 100.0" + "}}"); + INVALIDATE(s, "101.5", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100, \"exclusiveMaximum\": true, \"actual\": 101.5" + "}}"); } TEST(SchemaValidator, Number_RangeInt) { @@ -484,19 +702,63 @@ TEST(SchemaValidator, Number_RangeInt) { sd.Parse("{\"type\":\"number\",\"minimum\":-100,\"maximum\":-1,\"exclusiveMaximum\":true}"); SchemaDocument s(sd); - INVALIDATE(s, "-101", "", "minimum", ""); - INVALIDATE(s, "-100.1", "", "minimum", ""); + INVALIDATE(s, "-101", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -100, \"actual\": -101" + "}}"); + INVALIDATE(s, "-100.1", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -100, \"actual\": -100.1" + "}}"); VALIDATE(s, "-100", true); VALIDATE(s, "-2", true); - INVALIDATE(s, "-1", "", "maximum", ""); - INVALIDATE(s, "-0.9", "", "maximum", ""); - INVALIDATE(s, "0", "", "maximum", ""); - INVALIDATE(s, "2147483647", "", "maximum", ""); // int max - INVALIDATE(s, "2147483648", "", "maximum", ""); // unsigned first - INVALIDATE(s, "4294967295", "", "maximum", ""); // unsigned max - INVALIDATE(s, "9223372036854775808", "", "maximum", ""); - INVALIDATE(s, "18446744073709551614", "", "maximum", ""); - INVALIDATE(s, "18446744073709551615", "", "maximum", ""); + INVALIDATE(s, "-1", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -1" + "}}"); + INVALIDATE(s, "-0.9", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": -0.9" + "}}"); + INVALIDATE(s, "0", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 0" + "}}"); + INVALIDATE(s, "2147483647", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483647" + "}}"); // int max + INVALIDATE(s, "2147483648", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 2147483648" + "}}"); // unsigned first + INVALIDATE(s, "4294967295", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 4294967295" + "}}"); // unsigned max + INVALIDATE(s, "9223372036854775808", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808" + "}}"); + INVALIDATE(s, "18446744073709551614", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614" + "}}"); + INVALIDATE(s, "18446744073709551615", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": -1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615" + "}}"); } TEST(SchemaValidator, Number_RangeDouble) { @@ -504,23 +766,75 @@ TEST(SchemaValidator, Number_RangeDouble) { sd.Parse("{\"type\":\"number\",\"minimum\":0.1,\"maximum\":100.1,\"exclusiveMaximum\":true}"); SchemaDocument s(sd); - INVALIDATE(s, "-9223372036854775808", "", "minimum", ""); - INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min - INVALIDATE(s, "-1", "", "minimum", ""); + INVALIDATE(s, "-9223372036854775808", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 0.1, \"actual\": -9223372036854775808" + "}}"); + INVALIDATE(s, "-2147483648", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 0.1, \"actual\": -2147483648" + "}}"); // int min + INVALIDATE(s, "-1", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 0.1, \"actual\": -1" + "}}"); VALIDATE(s, "0.1", true); VALIDATE(s, "10", true); VALIDATE(s, "99", true); VALIDATE(s, "100", true); - INVALIDATE(s, "101", "", "maximum", ""); - INVALIDATE(s, "101.5", "", "maximum", ""); - INVALIDATE(s, "18446744073709551614", "", "maximum", ""); - INVALIDATE(s, "18446744073709551615", "", "maximum", ""); - INVALIDATE(s, "2147483647", "", "maximum", ""); // int max - INVALIDATE(s, "2147483648", "", "maximum", ""); // unsigned first - INVALIDATE(s, "4294967295", "", "maximum", ""); // unsigned max - INVALIDATE(s, "9223372036854775808", "", "maximum", ""); - INVALIDATE(s, "18446744073709551614", "", "maximum", ""); - INVALIDATE(s, "18446744073709551615", "", "maximum", ""); + INVALIDATE(s, "101", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101" + "}}"); + INVALIDATE(s, "101.5", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 101.5" + "}}"); + INVALIDATE(s, "18446744073709551614", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614" + "}}"); + INVALIDATE(s, "18446744073709551615", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615" + "}}"); + INVALIDATE(s, "2147483647", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483647" + "}}"); // int max + INVALIDATE(s, "2147483648", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 2147483648" + "}}"); // unsigned first + INVALIDATE(s, "4294967295", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 4294967295" + "}}"); // unsigned max + INVALIDATE(s, "9223372036854775808", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 9223372036854775808" + "}}"); + INVALIDATE(s, "18446744073709551614", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551614" + "}}"); + INVALIDATE(s, "18446744073709551615", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 100.1, \"exclusiveMaximum\": true, \"actual\": 18446744073709551615" + "}}"); } TEST(SchemaValidator, Number_RangeDoubleU64Boundary) { @@ -528,15 +842,43 @@ TEST(SchemaValidator, Number_RangeDoubleU64Boundary) { sd.Parse("{\"type\":\"number\",\"minimum\":9223372036854775808.0,\"maximum\":18446744073709550000.0}"); SchemaDocument s(sd); - INVALIDATE(s, "-9223372036854775808", "", "minimum", ""); - INVALIDATE(s, "-2147483648", "", "minimum", ""); // int min - INVALIDATE(s, "0", "", "minimum", ""); - INVALIDATE(s, "2147483647", "", "minimum", ""); // int max - INVALIDATE(s, "2147483648", "", "minimum", ""); // unsigned first - INVALIDATE(s, "4294967295", "", "minimum", ""); // unsigned max + INVALIDATE(s, "-9223372036854775808", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808.0, \"actual\": -9223372036854775808" + "}}"); + INVALIDATE(s, "-2147483648", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808.0, \"actual\": -2147483648" + "}}"); // int min + INVALIDATE(s, "0", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808.0, \"actual\": 0" + "}}"); + INVALIDATE(s, "2147483647", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808.0, \"actual\": 2147483647" + "}}"); // int max + INVALIDATE(s, "2147483648", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808.0, \"actual\": 2147483648" + "}}"); // unsigned first + INVALIDATE(s, "4294967295", "", "minimum", "", + "{ \"minimum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 9223372036854775808.0, \"actual\": 4294967295" + "}}"); // unsigned max VALIDATE(s, "9223372036854775808", true); VALIDATE(s, "18446744073709540000", true); - INVALIDATE(s, "18446744073709551615", "", "maximum", ""); + INVALIDATE(s, "18446744073709551615", "", "maximum", "", + "{ \"maximum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 18446744073709550000.0, \"actual\": 18446744073709551615" + "}}"); } TEST(SchemaValidator, Number_MultipleOf) { @@ -548,13 +890,33 @@ TEST(SchemaValidator, Number_MultipleOf) { VALIDATE(s, "10", true); VALIDATE(s, "-10", true); VALIDATE(s, "20", true); - INVALIDATE(s, "23", "", "multipleOf", ""); - INVALIDATE(s, "-2147483648", "", "multipleOf", ""); // int min + INVALIDATE(s, "23", "", "multipleOf", "", + "{ \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 10.0, \"actual\": 23" + "}}"); + INVALIDATE(s, "-2147483648", "", "multipleOf", "", + "{ \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 10.0, \"actual\": -2147483648" + "}}"); // int min VALIDATE(s, "-2147483640", true); - INVALIDATE(s, "2147483647", "", "multipleOf", ""); // int max - INVALIDATE(s, "2147483648", "", "multipleOf", ""); // unsigned first + INVALIDATE(s, "2147483647", "", "multipleOf", "", + "{ \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 10.0, \"actual\": 2147483647" + "}}"); // int max + INVALIDATE(s, "2147483648", "", "multipleOf", "", + "{ \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 10.0, \"actual\": 2147483648" + "}}"); // unsigned first VALIDATE(s, "2147483650", true); - INVALIDATE(s, "4294967295", "", "multipleOf", ""); // unsigned max + INVALIDATE(s, "4294967295", "", "multipleOf", "", + "{ \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 10.0, \"actual\": 4294967295" + "}}"); // unsigned max VALIDATE(s, "4294967300", true); } @@ -565,7 +927,11 @@ TEST(SchemaValidator, Number_MultipleOfOne) { VALIDATE(s, "42", true); VALIDATE(s, "42.0", true); - INVALIDATE(s, "3.1415926", "", "multipleOf", ""); + INVALIDATE(s, "3.1415926", "", "multipleOf", "", + "{ \"multipleOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 1, \"actual\": 3.1415926" + "}}"); } TEST(SchemaValidator, Object) { @@ -575,8 +941,16 @@ TEST(SchemaValidator, Object) { VALIDATE(s, "{\"key\":\"value\",\"another_key\":\"another_value\"}", true); VALIDATE(s, "{\"Sun\":1.9891e30,\"Jupiter\":1.8986e27,\"Saturn\":5.6846e26,\"Neptune\":10.243e25,\"Uranus\":8.6810e25,\"Earth\":5.9736e24,\"Venus\":4.8685e24,\"Mars\":6.4185e23,\"Mercury\":3.3022e23,\"Moon\":7.349e22,\"Pluto\":1.25e22}", true); - INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", ""); - INVALIDATE(s, "\"Not an object\"", "", "type", ""); + INVALIDATE(s, "[\"An\", \"array\", \"not\", \"an\", \"object\"]", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"object\"], \"actual\": \"array\"" + "}}"); + INVALIDATE(s, "\"Not an object\"", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"object\"], \"actual\": \"string\"" + "}}"); } TEST(SchemaValidator, Object_Properties) { @@ -594,7 +968,17 @@ TEST(SchemaValidator, Object_Properties) { SchemaDocument s(sd); VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true); - INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number"); + INVALIDATE(s, "{ \"number\": \"1600\", \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", "/properties/number", "type", "/number", + "{ \"type\": {" + " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\"," + " \"expected\": [\"number\"], \"actual\": \"string\"" + "}}"); + INVALIDATE(s, "{ \"number\": \"One\", \"street_name\": \"Microsoft\", \"street_type\": \"Way\" }", + "/properties/number", "type", "/number", + "{ \"type\": {" + " \"instanceRef\": \"#/number\", \"schemaRef\": \"#/properties/number\"," + " \"expected\": [\"number\"], \"actual\": \"string\"" + "}}"); // fail fast VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\" }", true); VALIDATE(s, "{}", true); VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true); @@ -618,7 +1002,11 @@ TEST(SchemaValidator, Object_AdditionalPropertiesBoolean) { SchemaDocument s(sd); VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true); - INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction"); + INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", "", "additionalProperties", "/direction", + "{ \"additionalProperties\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"disallowed\": \"direction\"" + "}}"); } TEST(SchemaValidator, Object_AdditionalPropertiesObject) { @@ -639,7 +1027,11 @@ TEST(SchemaValidator, Object_AdditionalPropertiesObject) { VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\" }", true); VALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"direction\": \"NW\" }", true); - INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number"); + INVALIDATE(s, "{ \"number\": 1600, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\", \"office_number\": 201 }", "/additionalProperties", "type", "/office_number", + "{ \"type\": {" + " \"instanceRef\": \"#/office_number\", \"schemaRef\": \"#/additionalProperties\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + "}}"); } TEST(SchemaValidator, Object_Required) { @@ -659,7 +1051,16 @@ TEST(SchemaValidator, Object_Required) { VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\" }", true); VALIDATE(s, "{ \"name\": \"William Shakespeare\", \"email\" : \"bill@stratford-upon-avon.co.uk\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\", \"authorship\" : \"in question\"}", true); - INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", ""); + INVALIDATE(s, "{ \"name\": \"William Shakespeare\", \"address\" : \"Henley Street, Stratford-upon-Avon, Warwickshire, England\" }", "", "required", "", + "{ \"required\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"missing\": [\"email\"]" + "}}"); + INVALIDATE(s, "{}", "", "required", "", + "{ \"required\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"missing\": [\"name\", \"email\"]" + "}}"); } @@ -668,11 +1069,23 @@ TEST(SchemaValidator, Object_PropertiesRange) { sd.Parse("{\"type\":\"object\", \"minProperties\":2, \"maxProperties\":3}"); SchemaDocument s(sd); - INVALIDATE(s, "{}", "", "minProperties", ""); - INVALIDATE(s, "{\"a\":0}", "", "minProperties", ""); + INVALIDATE(s, "{}", "", "minProperties", "", + "{ \"minProperties\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 2, \"actual\": 0" + "}}"); + INVALIDATE(s, "{\"a\":0}", "", "minProperties", "", + "{ \"minProperties\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 2, \"actual\": 1" + "}}"); VALIDATE(s, "{\"a\":0,\"b\":1}", true); VALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2}", true); - INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", ""); + INVALIDATE(s, "{\"a\":0,\"b\":1,\"c\":2,\"d\":3}", "", "maxProperties", "", + "{ \"maxProperties\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\", " + " \"expected\": 3, \"actual\": 4" + "}}"); } TEST(SchemaValidator, Object_PropertyDependencies) { @@ -683,19 +1096,25 @@ TEST(SchemaValidator, Object_PropertyDependencies) { " \"properties\": {" " \"name\": { \"type\": \"string\" }," " \"credit_card\": { \"type\": \"number\" }," + " \"cvv_code\": { \"type\": \"number\" }," " \"billing_address\": { \"type\": \"string\" }" " }," " \"required\": [\"name\"]," " \"dependencies\": {" - " \"credit_card\": [\"billing_address\"]" + " \"credit_card\": [\"cvv_code\", \"billing_address\"]" " }" "}"); SchemaDocument s(sd); - VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"billing_address\": \"555 Debtor's Lane\" }", true); - INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", ""); + VALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555, \"cvv_code\": 777, " + "\"billing_address\": \"555 Debtor's Lane\" }", true); + INVALIDATE(s, "{ \"name\": \"John Doe\", \"credit_card\": 5555555555555555 }", "", "dependencies", "", + "{ \"dependencies\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": {\"credit_card\": [\"cvv_code\", \"billing_address\"]}" + "}}"); VALIDATE(s, "{ \"name\": \"John Doe\"}", true); - VALIDATE(s, "{ \"name\": \"John Doe\", \"billing_address\": \"555 Debtor's Lane\" }", true); + VALIDATE(s, "{ \"name\": \"John Doe\", \"cvv_code\": 777, \"billing_address\": \"555 Debtor's Lane\" }", true); } TEST(SchemaValidator, Object_SchemaDependencies) { @@ -720,7 +1139,16 @@ TEST(SchemaValidator, Object_SchemaDependencies) { SchemaDocument s(sd); VALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555,\"billing_address\" : \"555 Debtor's Lane\"}", true); - INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", ""); + INVALIDATE(s, "{\"name\": \"John Doe\", \"credit_card\" : 5555555555555555 }", "", "dependencies", "", + "{ \"dependencies\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": {" + " \"credit_card\": {" + " \"required\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/dependencies/credit_card\"," + " \"missing\": [\"billing_address\"]" + " } } }" + "}}"); VALIDATE(s, "{\"name\": \"John Doe\", \"billing_address\" : \"555 Debtor's Lane\"}", true); } @@ -739,11 +1167,77 @@ TEST(SchemaValidator, Object_PatternProperties) { VALIDATE(s, "{ \"S_25\": \"This is a string\" }", true); VALIDATE(s, "{ \"I_0\": 42 }", true); - INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0"); - INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42"); + INVALIDATE(s, "{ \"S_0\": 42 }", "", "patternProperties", "/S_0", + "{ \"type\": {" + " \"instanceRef\": \"#/S_0\", \"schemaRef\": \"#/patternProperties/%5ES_\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + "}}"); + INVALIDATE(s, "{ \"I_42\": \"This is a string\" }", "", "patternProperties", "/I_42", + "{ \"type\": {" + " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\"," + " \"expected\": [\"integer\"], \"actual\": \"string\"" + "}}"); VALIDATE(s, "{ \"keyword\": \"value\" }", true); } +TEST(SchemaValidator, Object_PattternProperties_ErrorConflict) { + Document sd; + sd.Parse( + "{" + " \"type\": \"object\"," + " \"patternProperties\": {" + " \"^I_\": { \"multipleOf\": 5 }," + " \"30$\": { \"multipleOf\": 6 }" + " }" + "}"); + SchemaDocument s(sd); + + VALIDATE(s, "{ \"I_30\": 30 }", true); + INVALIDATE(s, "{ \"I_30\": 7 }", "", "patternProperties", "/I_30", + "{ \"multipleOf\": [" + " {" + " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/%5EI_\"," + " \"expected\": 5, \"actual\": 7" + " }, {" + " \"instanceRef\": \"#/I_30\", \"schemaRef\": \"#/patternProperties/30%24\"," + " \"expected\": 6, \"actual\": 7" + " }" + "]}"); +} + +TEST(SchemaValidator, Object_Properties_PatternProperties) { + Document sd; + sd.Parse( + "{" + " \"type\": \"object\"," + " \"properties\": {" + " \"I_42\": { \"type\": \"integer\", \"minimum\": 73 }" + " }," + " \"patternProperties\": {" + " \"^I_\": { \"type\": \"integer\", \"multipleOf\": 6 }" + " }" + "}"); + SchemaDocument s(sd); + + VALIDATE(s, "{ \"I_6\": 6 }", true); + VALIDATE(s, "{ \"I_42\": 78 }", true); + INVALIDATE(s, "{ \"I_42\": 42 }", "", "patternProperties", "/I_42", + "{ \"minimum\": {" + " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\"," + " \"expected\": 73, \"actual\": 42" + "}}"); + INVALIDATE(s, "{ \"I_42\": 7 }", "", "patternProperties", "/I_42", + "{ \"minimum\": {" + " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/properties/I_42\"," + " \"expected\": 73, \"actual\": 7" + " }," + " \"multipleOf\": {" + " \"instanceRef\": \"#/I_42\", \"schemaRef\": \"#/patternProperties/%5EI_\"," + " \"expected\": 6, \"actual\": 7" + " }" + "}"); +} + TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) { Document sd; sd.Parse( @@ -762,7 +1256,11 @@ TEST(SchemaValidator, Object_PatternProperties_AdditionalProperties) { VALIDATE(s, "{ \"builtin\": 42 }", true); VALIDATE(s, "{ \"keyword\": \"value\" }", true); - INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword"); + INVALIDATE(s, "{ \"keyword\": 42 }", "/additionalProperties", "type", "/keyword", + "{ \"type\": {" + " \"instanceRef\": \"#/keyword\", \"schemaRef\": \"#/additionalProperties\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + "}}"); } #endif @@ -773,7 +1271,11 @@ TEST(SchemaValidator, Array) { VALIDATE(s, "[1, 2, 3, 4, 5]", true); VALIDATE(s, "[3, \"different\", { \"types\" : \"of values\" }]", true); - INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", ""); + INVALIDATE(s, "{\"Not\": \"an array\"}", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"array\"], \"actual\": \"object\"" + "}}"); } TEST(SchemaValidator, Array_ItemsList) { @@ -788,7 +1290,11 @@ TEST(SchemaValidator, Array_ItemsList) { SchemaDocument s(sd); VALIDATE(s, "[1, 2, 3, 4, 5]", true); - INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2"); + INVALIDATE(s, "[1, 2, \"3\", 4, 5]", "/items", "type", "/2", + "{ \"type\": {" + " \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items\"," + " \"expected\": [\"number\"], \"actual\": \"string\"" + "}}"); VALIDATE(s, "[]", true); } @@ -817,8 +1323,18 @@ TEST(SchemaValidator, Array_ItemsTuple) { SchemaDocument s(sd); VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true); - INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2"); - INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0"); + INVALIDATE(s, "[24, \"Sussex\", \"Drive\"]", "/items/2", "enum", "/2", + "{ \"enum\": { \"instanceRef\": \"#/2\", \"schemaRef\": \"#/items/2\" }}"); + INVALIDATE(s, "[\"Palais de l'Elysee\"]", "/items/0", "type", "/0", + "{ \"type\": {" + " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\"," + " \"expected\": [\"number\"], \"actual\": \"string\"" + "}}"); + INVALIDATE(s, "[\"Twenty-four\", \"Sussex\", \"Drive\"]", "/items/0", "type", "/0", + "{ \"type\": {" + " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items/0\"," + " \"expected\": [\"number\"], \"actual\": \"string\"" + "}}"); // fail fast VALIDATE(s, "[10, \"Downing\", \"Street\"]", true); VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", true); } @@ -850,7 +1366,11 @@ TEST(SchemaValidator, Array_AdditionalItmes) { VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\"]", true); VALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\"]", true); - INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4"); + INVALIDATE(s, "[1600, \"Pennsylvania\", \"Avenue\", \"NW\", \"Washington\"]", "", "items", "/4", + "{ \"additionalItems\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"disallowed\": 4" + "}}"); } TEST(SchemaValidator, Array_ItemsRange) { @@ -858,11 +1378,23 @@ TEST(SchemaValidator, Array_ItemsRange) { sd.Parse("{\"type\": \"array\",\"minItems\": 2,\"maxItems\" : 3}"); SchemaDocument s(sd); - INVALIDATE(s, "[]", "", "minItems", ""); - INVALIDATE(s, "[1]", "", "minItems", ""); + INVALIDATE(s, "[]", "", "minItems", "", + "{ \"minItems\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 2, \"actual\": 0" + "}}"); + INVALIDATE(s, "[1]", "", "minItems", "", + "{ \"minItems\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 2, \"actual\": 1" + "}}"); VALIDATE(s, "[1, 2]", true); VALIDATE(s, "[1, 2, 3]", true); - INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", ""); + INVALIDATE(s, "[1, 2, 3, 4]", "", "maxItems", "", + "{ \"maxItems\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 3, \"actual\": 4" + "}}"); } TEST(SchemaValidator, Array_UniqueItems) { @@ -871,7 +1403,16 @@ TEST(SchemaValidator, Array_UniqueItems) { SchemaDocument s(sd); VALIDATE(s, "[1, 2, 3, 4, 5]", true); - INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3"); + INVALIDATE(s, "[1, 2, 3, 3, 4]", "", "uniqueItems", "/3", + "{ \"uniqueItems\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"duplicates\": [2, 3]" + "}}"); + INVALIDATE(s, "[1, 2, 3, 3, 3]", "", "uniqueItems", "/3", + "{ \"uniqueItems\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"duplicates\": [2, 3]" + "}}"); // fail fast VALIDATE(s, "[]", true); } @@ -882,8 +1423,16 @@ TEST(SchemaValidator, Boolean) { VALIDATE(s, "true", true); VALIDATE(s, "false", true); - INVALIDATE(s, "\"true\"", "", "type", ""); - INVALIDATE(s, "0", "", "type", ""); + INVALIDATE(s, "\"true\"", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"boolean\"], \"actual\": \"string\"" + "}}"); + INVALIDATE(s, "0", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"boolean\"], \"actual\": \"integer\"" + "}}"); } TEST(SchemaValidator, Null) { @@ -892,9 +1441,21 @@ TEST(SchemaValidator, Null) { SchemaDocument s(sd); VALIDATE(s, "null", true); - INVALIDATE(s, "false", "", "type", ""); - INVALIDATE(s, "0", "", "type", ""); - INVALIDATE(s, "\"\"", "", "type", ""); + INVALIDATE(s, "false", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"null\"], \"actual\": \"boolean\"" + "}}"); + INVALIDATE(s, "0", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"null\"], \"actual\": \"integer\"" + "}}"); + INVALIDATE(s, "\"\"", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"null\"], \"actual\": \"string\"" + "}}"); } // Additional tests @@ -905,8 +1466,16 @@ TEST(SchemaValidator, ObjectInArray) { SchemaDocument s(sd); VALIDATE(s, "[\"a\"]", true); - INVALIDATE(s, "[1]", "/items", "type", "/0"); - INVALIDATE(s, "[{}]", "/items", "type", "/0"); + INVALIDATE(s, "[1]", "/items", "type", "/0", + "{ \"type\": {" + " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + "}}"); + INVALIDATE(s, "[{}]", "/items", "type", "/0", + "{ \"type\": {" + " \"instanceRef\": \"#/0\", \"schemaRef\": \"#/items\"," + " \"expected\": [\"string\"], \"actual\": \"object\"" + "}}"); } TEST(SchemaValidator, MultiTypeInObject) { @@ -924,7 +1493,11 @@ TEST(SchemaValidator, MultiTypeInObject) { VALIDATE(s, "{ \"tel\": 999 }", true); VALIDATE(s, "{ \"tel\": \"123-456\" }", true); - INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel"); + INVALIDATE(s, "{ \"tel\": true }", "/properties/tel", "type", "/tel", + "{ \"type\": {" + " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\"," + " \"expected\": [\"string\", \"integer\"], \"actual\": \"boolean\"" + "}}"); } TEST(SchemaValidator, MultiTypeWithObject) { @@ -942,7 +1515,11 @@ TEST(SchemaValidator, MultiTypeWithObject) { VALIDATE(s, "\"Hello\"", true); VALIDATE(s, "{ \"tel\": 999 }", true); - INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel"); + INVALIDATE(s, "{ \"tel\": \"fail\" }", "/properties/tel", "type", "/tel", + "{ \"type\": {" + " \"instanceRef\": \"#/tel\", \"schemaRef\": \"#/properties/tel\"," + " \"expected\": [\"integer\"], \"actual\": \"string\"" + "}}"); } TEST(SchemaValidator, AllOf_Nested) { @@ -959,11 +1536,88 @@ TEST(SchemaValidator, AllOf_Nested) { VALIDATE(s, "\"ok\"", true); VALIDATE(s, "\"OK\"", true); - INVALIDATE(s, "\"okay\"", "", "allOf", ""); - INVALIDATE(s, "\"o\"", "", "allOf", ""); - INVALIDATE(s, "\"n\"", "", "allOf", ""); - INVALIDATE(s, "\"too long\"", "", "allOf", ""); - INVALIDATE(s, "123", "", "allOf", ""); + INVALIDATE(s, "\"okay\"", "", "allOf", "", + "{ \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": [" + " {}, " + " {}, " + " { \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\"," + " \"errors\": [" + " {}, " + " { \"enum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"" + "}} ] }} ] }}"); + INVALIDATE(s, "\"o\"", "", "allOf", "", + "{ \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": [" + " { \"minLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," + " \"expected\": 2, \"actual\": \"o\"" + " }}," + " {}," + " {}" + " ]" + "}}"); + INVALIDATE(s, "\"n\"", "", "allOf", "", + "{ \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": [" + " { \"minLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," + " \"expected\": 2, \"actual\": \"n\"" + " }}," + " {}, " + " { \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\"," + " \"errors\": [" + " { \"enum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"" + " }}," + " { \"enum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"" + "}} ] }} ] }}"); + INVALIDATE(s, "\"too long\"", "", "allOf", "", + "{ \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": [" + " {}, " + " { \"maxLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\"," + " \"expected\": 5, \"actual\": \"too long\"" + " }}," + " { \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\"," + " \"errors\": [" + " { \"enum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"" + " }}," + " { \"enum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"" + "}} ] }} ] }}"); + INVALIDATE(s, "123", "", "allOf", "", + "{ \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"errors\": [" + " { \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + " }}," + " { \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + " }}," + " { \"allOf\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\"," + " \"errors\": [" + " { \"enum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"" + " }}, " + " { \"enum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"" + "}} ] }} ] }}"); } TEST(SchemaValidator, EscapedPointer) { @@ -976,7 +1630,11 @@ TEST(SchemaValidator, EscapedPointer) { " }" "}"); SchemaDocument s(sd); - INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1"); + INVALIDATE(s, "{\"~/\":true}", "/properties/~0~1", "type", "/~0~1", + "{ \"type\": {" + " \"instanceRef\": \"#/~0~1\", \"schemaRef\": \"#/properties/~0~1\"," + " \"expected\": [\"number\"], \"actual\": \"boolean\"" + "}}"); } template @@ -1026,6 +1684,10 @@ TEST(SchemaValidator, ValidateMetaSchema) { sb.Clear(); validator.GetInvalidDocumentPointer().StringifyUriFragment(sb); printf("Invalid document: %s\n", sb.GetString()); + sb.Clear(); + Writer w(sb); + validator.GetError().Accept(w); + printf("Validation error: %s\n", sb.GetString()); ADD_FAILURE(); } CrtAllocator::Free(json); @@ -1053,6 +1715,10 @@ TEST(SchemaValidator, ValidateMetaSchema_UTF16) { sb.Clear(); validator.GetInvalidDocumentPointer().StringifyUriFragment(sb); wprintf(L"Invalid document: %ls\n", sb.GetString()); + sb.Clear(); + Writer >, UTF16<> > w(sb); + validator.GetError().Accept(w); + printf("Validation error: %ls\n", sb.GetString()); ADD_FAILURE(); } CrtAllocator::Free(json); @@ -1260,6 +1926,15 @@ TEST(SchemaValidatingReader, Invalid) { EXPECT_TRUE(reader.GetInvalidSchemaPointer() == SchemaDocument::PointerType("")); EXPECT_TRUE(reader.GetInvalidDocumentPointer() == SchemaDocument::PointerType("")); EXPECT_TRUE(d.IsNull()); + Document e; + e.Parse( + "{ \"maxLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 3, \"actual\": \"ABCD\"" + "}}"); + if (e != reader.GetError()) { + ADD_FAILURE(); + } } TEST(SchemaValidatingWriter, Simple) { @@ -1284,6 +1959,13 @@ TEST(SchemaValidatingWriter, Simple) { EXPECT_FALSE(validator.IsValid()); EXPECT_TRUE(validator.GetInvalidSchemaPointer() == SchemaDocument::PointerType("")); EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType("")); + Document e; + e.Parse( + "{ \"maxLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": 3, \"actual\": \"ABCD\"" + "}}"); + EXPECT_EQ(e, validator.GetError()); } TEST(Schema, Issue848) { @@ -1305,7 +1987,11 @@ TEST(Schema, Issue552) { SchemaDocument s = ReturnSchemaDocument(); VALIDATE(s, "42", true); VALIDATE(s, "\"Life, the universe, and everything\"", true); - INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", ""); + INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"expected\": [\"string\", \"number\"], \"actual\": \"array\"" + "}}"); } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS @@ -1316,7 +2002,11 @@ TEST(SchemaValidator, Issue608) { SchemaDocument s(sd); VALIDATE(s, "{\"a\" : null, \"b\": null}", true); - INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", ""); + INVALIDATE(s, "{\"a\" : null, \"a\" : null}", "", "required", "", + "{ \"required\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," + " \"missing\": [\"b\"]" + "}}"); } // Fail to resolve $ref in allOf causes crash in SchemaValidator::StartObject() @@ -1361,7 +2051,13 @@ TEST(SchemaValidator, Ref_remote) { SchemaDocumentType s(sd, 0, 0, &provider); typedef GenericSchemaValidator >, MemoryPoolAllocator<> > SchemaValidatorType; typedef GenericPointer > PointerType; - INVALIDATE_(s, "null", "/integer", "type", "", SchemaValidatorType, PointerType); + INVALIDATE_(s, "null", "/integer", "type", "", + "{ \"type\": {" + " \"instanceRef\": \"#\"," + " \"schemaRef\": \"http://localhost:1234/subSchemas.json#/integer\"," + " \"expected\": [\"integer\"], \"actual\": \"null\"" + "}}", + SchemaValidatorType, PointerType); } #ifdef __clang__ From 384df14e6dc630269ae3ba9855e74ffb44fb6d80 Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Fri, 22 Sep 2017 21:20:17 +0700 Subject: [PATCH 057/128] Document schema violation format --- doc/Doxyfile.in | 1 + doc/schema-errors.md | 269 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) create mode 100644 doc/schema-errors.md diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index ca14233..4f23a79 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -776,6 +776,7 @@ INPUT = readme.md \ doc/dom.md \ doc/sax.md \ doc/schema.md \ + doc/schema-errors.md \ doc/performance.md \ doc/internals.md \ doc/faq.md diff --git a/doc/schema-errors.md b/doc/schema-errors.md new file mode 100644 index 0000000..f82120e --- /dev/null +++ b/doc/schema-errors.md @@ -0,0 +1,269 @@ +# Schema violation reporting + +(Unreleased as of 2017-09-20) + +When validating an instance against a JSON Schema, +it is often desirable to report not only whether the instance is valid, +but also the ways in which it violates the schema. + +The `SchemaValidator` class +collects errors encountered during validation +into a JSON `Value`. +This error object can then be accessed as `validator.GetError()`. + +The structure of the error object is subject to change +in future versions of RapidJSON, +as there is no standard schema for violations. +The details below this point are provisional only. + +[TOC] + +# General provisions {#General} + +Validation of an instance value against a schema +produces an error value. +The error value is always an object. +An empty object `{}` indicates the instance is valid. + +* The name of each member + corresponds to the JSON Schema keyword that is violated. +* The value is either an object describing a single violation, + or an array of such objects. + +Each violation object contains two string-valued members +named `instanceRef` and `schemaRef`. +`instanceRef` contains the URI fragment serialization +of a JSON Pointer to the instance subobject +in which the violation was detected. +`schemaRef` contains the URI of the schema +and the fragment serialization of a JSON Pointer +to the subschema that was violated. + +Individual violation objects can contain other keyword-specific members. +These are detailed further. + +For example, validating this instance: + +~~~json +{"numbers": [1, 2, "3", 4, 5]} +~~~ + +against this schema: + +~~~json +{ + "type": "object", + "properties": { + "numbers": {"$ref": "numbers.schema.json"} + } +} +~~~ + +where `numbers.schema.json` refers +(via a suitable `IRemoteSchemaDocumentProvider`) +to this schema: + +~~~json +{ + "type": "array", + "items": {"type": "number"} +} +~~~ + +produces the following error object: + +~~~json +{ + "type": { + "instanceRef": "#/numbers/2", + "schemaRef": "numbers.schema.json#/items", + "expected": ["number"], + "actual": "string" + } +} +~~~ + +# Validation keywords for numbers {#numbers} + +## multipleOf {#multipleOf} + +* `expected`: required number strictly greater than 0. + The value of the `multipleOf` keyword specified in the schema. +* `actual`: required number. + The instance value. + +## maximum {#maximum} + +* `expected`: required number. + The value of the `maximum` keyword specified in the schema. +* `exclusiveMaximum`: optional boolean. + This will be true if the schema specified `"exclusiveMaximum": true`, + and will be omitted otherwise. +* `actual`: required number. + The instance value. + +## minimum {#minimum} + +* `expected`: required number. + The value of the `minimum` keyword specified in the schema. +* `exclusiveMinimum`: optional boolean. + This will be true if the schema specified `"exclusiveMinimum": true`, + and will be omitted otherwise. +* `actual`: required number. + The instance value. + +# Validation keywords for strings {#strings} + +## maxLength {#maxLength} + +* `expected`: required number greater than or equal to 0. + The value of the `maxLength` keyword specified in the schema. +* `actual`: required string. + The instance value. + +## minLength {#minLength} + +* `expected`: required number greater than or equal to 0. + The value of the `minLength` keyword specified in the schema. +* `actual`: required string. + The instance value. + +## pattern {#pattern} + +* `actual`: required string. + The instance value. + +(The expected pattern is not reported +because the internal representation in `SchemaDocument` +does not store the pattern in original string form.) + +# Validation keywords for arrays {#arrays} + +## additionalItems {#additionalItems} + +This keyword is reported +when the value of `items` schema keyword is an array, +the value of `additionalItems` is `false`, +and the instance is an array +with more items than specified in the `items` array. + +* `disallowed`: required integer greater than or equal to 0. + The index of the first item that has no corresponding schema. + +## maxItems and minItems {#maxItems} + +* `expected`: required integer greater than or equal to 0. + The value of `maxItems` (respectively, `minItems`) + specified in the schema. +* `actual`: required integer greater than or equal to 0. + Number of items in the instance array. + +## uniqueItems {#uniqueItems} + +* `duplicates`: required array + whose items are integers greater than or equal to 0. + Indices of items of the instance that are equal. + +(RapidJSON only reports the first two equal items, +for performance reasons.) + +# Validation keywords for objects + +## maxProperties and minProperties {#maxProperties} + +* `expected`: required integer greater than or equal to 0. + The value of `maxProperties` (respectively, `minProperties`) + specified in the schema. +* `actual`: required integer greater than or equal to 0. + Number of properties in the instance object. + +## required {#required} + +* `missing`: required array of one or more unique strings. + The names of properties + that are listed in the value of the `required` schema keyword + but not present in the instance object. + +## additionalProperties {#additionalProperties} + +This keyword is reported +when the schema specifies `additionalProperties: false` +and the name of a property of the instance is +neither listed in the `properties` keyword +nor matches any regular expression in the `patternProperties` keyword. + +* `disallowed`: required string. + Name of the offending property of the instance. + +(For performance reasons, +RapidJSON only reports the first such property encountered.) + +## dependencies {#dependencies} + +* `errors`: required object with one or more properties. + Names and values of its properties are described below. + +Recall that JSON Schema Draft 04 supports +*schema dependencies*, +where presence of a named *controlling* property +requires the instance object to be valid against a subschema, +and *property dependencies*, +where presence of a controlling property +requires other *dependent* properties to be also present. + +For a violated schema dependency, +`errors` will contain a property +with the name of the controlling property +and its value will be the error object +produced by validating the instance object +against the dependent schema. + +For a violated property dependency, +`errors` will contain a property +with the name of the controlling property +and its value will be an array of one or more unique strings +listing the missing dependent properties. + +# Validation keywords for any instance type {#anytypes} + +## enum {#enum} + +This keyword has no additional properties +beyond `instanceRef` and `schemaRef`. + +* The allowed values are not listed + because `SchemaDocument` does not store them in original form. +* The violating value is not reported + because it might be unwieldy. + +If you need to report these details to your users, +you can access the necessary information +by following `instanceRef` and `schemaRef`. + +## type {#type} + +* `expected`: required array of one or more unique strings, + each of which is one of the seven primitive types + defined by the JSON Schema Draft 04 Core specification. + Lists the types allowed by the `type` schema keyword. +* `actual`: required string, also one of seven primitive types. + The primitive type of the instance. + +## allOf, anyOf, and oneOf {#allOf} + +* `errors`: required array of at least one object. + There will be as many items as there are subschemas + in the `allOf`, `anyOf` or `oneOf` schema keyword, respectively. + Each item will be the error value + produced by validating the instance + against the corresponding subschema. + +For `allOf`, at least one error value will be non-empty. +For `anyOf`, all error values will be non-empty. +For `oneOf`, either all error values will be non-empty, +or more than one will be empty. + +## not {#not} + +This keyword has no additional properties +apart from `instanceRef` and `schemaRef`. From a4b62ff61be74061bb015c78770f48d6247c413b Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Fri, 22 Sep 2017 21:35:27 +0700 Subject: [PATCH 058/128] Update schemavalidator example to demonstrate GetError() --- example/schemavalidator/schemavalidator.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/example/schemavalidator/schemavalidator.cpp b/example/schemavalidator/schemavalidator.cpp index ce36ea9..06bbe4d 100644 --- a/example/schemavalidator/schemavalidator.cpp +++ b/example/schemavalidator/schemavalidator.cpp @@ -6,6 +6,7 @@ #include "rapidjson/filereadstream.h" #include "rapidjson/schema.h" #include "rapidjson/stringbuffer.h" +#include "rapidjson/prettywriter.h" using namespace rapidjson; @@ -67,6 +68,11 @@ int main(int argc, char *argv[]) { sb.Clear(); validator.GetInvalidDocumentPointer().StringifyUriFragment(sb); fprintf(stderr, "Invalid document: %s\n", sb.GetString()); + // Detailed violation report is available as a JSON value + sb.Clear(); + PrettyWriter w(sb); + validator.GetError().Accept(w); + fprintf(stderr, "Error report:\n%s\n", sb.GetString()); return EXIT_FAILURE; } } From 0b8adabab7f32dd9addc517aeb4c32b9da37e411 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 29 Sep 2017 09:44:05 +0800 Subject: [PATCH 059/128] Fix #1071 gitbook link --- readme.md | 2 +- readme.zh-cn.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index be22e20..b833a98 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights * RapidJSON Documentation * [English](http://rapidjson.org/) * [简体中文](http://rapidjson.org/zh-cn/) - * [GitBook](https://www.gitbook.com/book/Tencent/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. + * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. ## Build status diff --git a/readme.zh-cn.md b/readme.zh-cn.md index bca8897..f4ddaa8 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -12,7 +12,7 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights * RapidJSON 文档 * [English](http://rapidjson.org/) * [简体中文](http://rapidjson.org/zh-cn/) - * [GitBook](https://www.gitbook.com/book/Tencent/rapidjson/) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 + * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 ## Build 状态 From 2a0bc6062b38ed40586bd8e1945835698b95a9c1 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 29 Sep 2017 09:53:00 +0800 Subject: [PATCH 060/128] Update gitbook zh-cn link --- readme.zh-cn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.zh-cn.md b/readme.zh-cn.md index f4ddaa8..ccf1669 100644 --- a/readme.zh-cn.md +++ b/readme.zh-cn.md @@ -12,7 +12,7 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights * RapidJSON 文档 * [English](http://rapidjson.org/) * [简体中文](http://rapidjson.org/zh-cn/) - * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 + * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/details/zh-cn) 可下载 PDF/EPUB/MOBI,但不含 API 参考手册。 ## Build 状态 From b16ff281f854564e2669b2c3f4871793ddc51fc3 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Tue, 26 Sep 2017 15:39:06 +0800 Subject: [PATCH 061/128] Add feature of locating line and column number of error --- include/rapidjson/document.h | 11 ++++++++- include/rapidjson/error/error.h | 8 +++++++ include/rapidjson/stream.h | 42 +++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 93b091f..de65740 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2219,14 +2219,17 @@ public: \return The document itself for fluent API. */ template - GenericDocument& ParseStream(InputStream& is) { + GenericDocument& ParseStream(InputStream& is_) { GenericReader reader( stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); + GenericStreamWrapper is(is_); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { 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 + } else { + parseResult_.SetPos(is.line_, is.col_); } return *this; } @@ -2355,6 +2358,12 @@ public: //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorLine() const { return parseResult_.Line(); } + + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorColumn() const { return parseResult_.Col(); } //! Implicit conversion to get the last parse result #ifndef __clang // -Wdocumentation diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index 9311d2f..be80579 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -116,6 +116,10 @@ public: ParseErrorCode Code() const { return code_; } //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } + //! Get the position of line number if error exists. + size_t Line() const { return line_; } + //! Get the position of column number if error exists. + size_t Col() const { return col_; } //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } @@ -134,10 +138,14 @@ public: void Clear() { Set(kParseErrorNone); } //! Update error code and offset. void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } + //! Update line number and column number of the error position + void SetPos(size_t line, size_t col) { line_ = line; col_ = col; } private: ParseErrorCode code_; size_t offset_; + size_t line_; + size_t col_; }; //! Function pointer type of GetParseError(). diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index fef82c2..4e4ba80 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -100,6 +100,48 @@ inline void PutN(Stream& stream, Ch c, size_t n) { PutUnsafe(stream, c); } +/////////////////////////////////////////////////////////////////////////////// +// GenericStreamWrapper + +//! A Stream Wrapper +/*! \tThis string stream is designed for counting line and column number + \tof the error (if exists) position, while just forwarding any received + \tmessage to the origin stream. + \note implements Stream concept +*/ +template +class GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + size_t line_; + size_t col_; + GenericStreamWrapper(InputStream& is): is_(is), line_(1), col_(0) {} + + Ch Peek() const { return is_.Peek(); } + + // counting line and column number + Ch Take() { + Ch ch = is_.Take(); + if(ch == '\n') { + line_ ++; + col_ = 0; + } else { + col_ ++; + } + return ch; + } + size_t Tell() { return is_.Tell(); } + + Ch* PutBegin() { return is_.PutBegin(); } + void Put(Ch ch) { return is_.Put(ch); } + void Flush() { return is_.Flush(); } + size_t PutEnd(Ch* ch) { is_.PutEnd(ch); } + + const Ch* Peek4() const { is_.Peek4(); } +private: + InputStream& is_; +}; + /////////////////////////////////////////////////////////////////////////////// // StringStream From 79d9c71f98b0f1cfea5fae2fe33595efcbf79028 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Tue, 26 Sep 2017 16:03:09 +0800 Subject: [PATCH 062/128] fix stream wrapper initializer fix initialization warning add special wrapper for AutoUTFInputStream --- include/rapidjson/error/error.h | 4 ++-- include/rapidjson/stream.h | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index be80579..618a6cf 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -108,9 +108,9 @@ struct ParseResult { typedef bool (ParseResult::*BooleanType)() const; public: //! Default constructor, no error. - ParseResult() : code_(kParseErrorNone), offset_(0) {} + ParseResult() : code_(kParseErrorNone), offset_(0), line_(0), col_(0) {} //! Constructor to set an error. - ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset), line_(0), col_(0) {} //! Get the error code. ParseErrorCode Code() const { return code_; } diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index 4e4ba80..a315d3f 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -115,7 +115,7 @@ public: typedef typename Encoding::Ch Ch; size_t line_; size_t col_; - GenericStreamWrapper(InputStream& is): is_(is), line_(1), col_(0) {} + GenericStreamWrapper(InputStream& is): line_(1), col_(0), is_(is) {} Ch Peek() const { return is_.Peek(); } @@ -133,11 +133,17 @@ public: size_t Tell() { return is_.Tell(); } Ch* PutBegin() { return is_.PutBegin(); } - void Put(Ch ch) { return is_.Put(ch); } - void Flush() { return is_.Flush(); } - size_t PutEnd(Ch* ch) { is_.PutEnd(ch); } + void Put(Ch ch) { is_.Put(ch); } + void Flush() { is_.Flush(); } + size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } - const Ch* Peek4() const { is_.Peek4(); } + // wrapper for MemoryStream + const Ch* Peek4() const { return is_.Peek4(); } + + // wrapper for AutoUTFInputStream + UTFType GetType() const { return is_.GetType(); } + bool HasBOM() const { return is_.HasBOM(); } + private: InputStream& is_; }; From 143641c75abaf6f111c79152b76996324ed3ad19 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Wed, 27 Sep 2017 13:58:16 +0800 Subject: [PATCH 063/128] suppress C4512, C4702 warning --- include/rapidjson/stream.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index a315d3f..556c30a 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -109,6 +109,12 @@ inline void PutN(Stream& stream, Ch c, size_t n) { \tmessage to the origin stream. \note implements Stream concept */ + +#if defined(_MSC_VER) && _MSC_VER <= 1700 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // disable unreachable code +#endif + template class GenericStreamWrapper { public: @@ -135,7 +141,7 @@ public: Ch* PutBegin() { return is_.PutBegin(); } void Put(Ch ch) { is_.Put(ch); } void Flush() { is_.Flush(); } - size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } + size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } // wrapper for MemoryStream const Ch* Peek4() const { return is_.Peek4(); } @@ -146,8 +152,17 @@ public: private: InputStream& is_; + + // elimante vs2010-2013 C4512 warning by + // prohibiting copy constructor & assignment operator. + GenericStreamWrapper& operator=(const GenericStreamWrapper &); + GenericStreamWrapper(const GenericStreamWrapper&); }; +#if defined(_MSC_VER) && _MSC_VER <= 1700 +RAPIDJSON_DIAG_POP +#endif + /////////////////////////////////////////////////////////////////////////////// // StringStream From 799fdea9fc05aa74c2ebfb49340943195ac2e1dc Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Thu, 28 Sep 2017 16:57:52 +0800 Subject: [PATCH 064/128] add cursor wrapper --- include/rapidjson/cursorstreamwrapper.h | 59 +++++++++++++++++++++++++ include/rapidjson/document.h | 11 +---- include/rapidjson/error/error.h | 12 +---- include/rapidjson/stream.h | 37 +++++----------- 4 files changed, 72 insertions(+), 47 deletions(-) create mode 100644 include/rapidjson/cursorstreamwrapper.h diff --git a/include/rapidjson/cursorstreamwrapper.h b/include/rapidjson/cursorstreamwrapper.h new file mode 100644 index 0000000..5c752af --- /dev/null +++ b/include/rapidjson/cursorstreamwrapper.h @@ -0,0 +1,59 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ +#define RAPIDJSON_CURSORSTREAMWRAPPER_H_ + +#include "stream.h" + +RAPIDJSON_NAMESPACE_BEGIN + + +//! Cursor stream wrapper for counting line and column number if error exists. +/*! + \tparam InputStream Any stream that implements Stream Concept +*/ +template > +class CursorStreamWrapper : public GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + + CursorStreamWrapper(InputStream& is): + GenericStreamWrapper(is), line_(1), col_(0) {} + + // counting line and column number + Ch Take() { + Ch ch = this->is_.Take(); + if(ch == '\n') { + line_ ++; + col_ = 0; + } else { + col_ ++; + } + return ch; + } + + //! Get the error line number, if error exists. + size_t GetLine() const { return line_; } + //! Get the error column number, if error exists. + size_t GetColumn() const { return col_; } + +private: + size_t line_; //!< Current Line + size_t col_; //!< Current Column +}; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index de65740..93b091f 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2219,17 +2219,14 @@ public: \return The document itself for fluent API. */ template - GenericDocument& ParseStream(InputStream& is_) { + GenericDocument& ParseStream(InputStream& is) { GenericReader reader( stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); - GenericStreamWrapper is(is_); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { 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 - } else { - parseResult_.SetPos(is.line_, is.col_); } return *this; } @@ -2358,12 +2355,6 @@ public: //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorLine() const { return parseResult_.Line(); } - - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorColumn() const { return parseResult_.Col(); } //! Implicit conversion to get the last parse result #ifndef __clang // -Wdocumentation diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index 618a6cf..9311d2f 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -108,18 +108,14 @@ struct ParseResult { typedef bool (ParseResult::*BooleanType)() const; public: //! Default constructor, no error. - ParseResult() : code_(kParseErrorNone), offset_(0), line_(0), col_(0) {} + ParseResult() : code_(kParseErrorNone), offset_(0) {} //! Constructor to set an error. - ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset), line_(0), col_(0) {} + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} //! Get the error code. ParseErrorCode Code() const { return code_; } //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } - //! Get the position of line number if error exists. - size_t Line() const { return line_; } - //! Get the position of column number if error exists. - size_t Col() const { return col_; } //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } @@ -138,14 +134,10 @@ public: void Clear() { Set(kParseErrorNone); } //! Update error code and offset. void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } - //! Update line number and column number of the error position - void SetPos(size_t line, size_t col) { line_ = line; col_ = col; } private: ParseErrorCode code_; size_t offset_; - size_t line_; - size_t col_; }; //! Function pointer type of GetParseError(). diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index 556c30a..f492797 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -104,40 +104,28 @@ inline void PutN(Stream& stream, Ch c, size_t n) { // GenericStreamWrapper //! A Stream Wrapper -/*! \tThis string stream is designed for counting line and column number - \tof the error (if exists) position, while just forwarding any received - \tmessage to the origin stream. +/*! \tThis string stream is a wrapper for any stream by just forwarding any + \treceived message to the origin stream. \note implements Stream concept */ -#if defined(_MSC_VER) && _MSC_VER <= 1700 +#if defined(_MSC_VER) && _MSC_VER <= 1800 RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4702) // disable unreachable code +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif -template +template > class GenericStreamWrapper { public: typedef typename Encoding::Ch Ch; size_t line_; size_t col_; - GenericStreamWrapper(InputStream& is): line_(1), col_(0), is_(is) {} + GenericStreamWrapper(InputStream& is): is_(is) {} Ch Peek() const { return is_.Peek(); } - - // counting line and column number - Ch Take() { - Ch ch = is_.Take(); - if(ch == '\n') { - line_ ++; - col_ = 0; - } else { - col_ ++; - } - return ch; - } + Ch Take() { return is_.Take(); } size_t Tell() { return is_.Tell(); } - Ch* PutBegin() { return is_.PutBegin(); } void Put(Ch ch) { is_.Put(ch); } void Flush() { is_.Flush(); } @@ -150,16 +138,11 @@ public: UTFType GetType() const { return is_.GetType(); } bool HasBOM() const { return is_.HasBOM(); } -private: +protected: InputStream& is_; - - // elimante vs2010-2013 C4512 warning by - // prohibiting copy constructor & assignment operator. - GenericStreamWrapper& operator=(const GenericStreamWrapper &); - GenericStreamWrapper(const GenericStreamWrapper&); }; -#if defined(_MSC_VER) && _MSC_VER <= 1700 +#if defined(_MSC_VER) && _MSC_VER <= 1800 RAPIDJSON_DIAG_POP #endif From 66541b8926c349cea4bee16630a3d38693da4588 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Fri, 29 Sep 2017 17:24:07 +0800 Subject: [PATCH 065/128] add unit test for cursorstreamwrapper --- test/unittest/CMakeLists.txt | 1 + test/unittest/cursorstreamwrappertest.cpp | 115 ++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 test/unittest/cursorstreamwrappertest.cpp diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index fdf0ad0..072b7b1 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -3,6 +3,7 @@ include(CheckCXXCompilerFlag) set(UNITTEST_SOURCES allocatorstest.cpp bigintegertest.cpp + cursorstreamwrappertest.cpp documenttest.cpp dtoatest.cpp encodedstreamtest.cpp diff --git a/test/unittest/cursorstreamwrappertest.cpp b/test/unittest/cursorstreamwrappertest.cpp new file mode 100644 index 0000000..a116248 --- /dev/null +++ b/test/unittest/cursorstreamwrappertest.cpp @@ -0,0 +1,115 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#include "unittest.h" +#include "rapidjson/document.h" +#include "rapidjson/cursorstreamwrapper.h" + +using namespace rapidjson; + +// static const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + +bool testJson(const char *json, size_t &line, size_t &col) { + StringStream ss(json); + CursorStreamWrapper csw(ss); + Document document; + document.ParseStream(csw); + bool ret = document.HasParseError(); + if (ret) { + col = csw.GetColumn(); + line = csw.GetLine(); + } + return ret; +} + +TEST(CursorStreamWrapper, MissingFirstBracket) { + const char json[] = "\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 3); + EXPECT_EQ(col, 0); +} + +TEST(CursorStreamWrapper, MissingQuotes) { + const char json[] = "{\"string\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 1); + EXPECT_EQ(col, 8); +} + +TEST(CursorStreamWrapper, MissingColon) { + const char json[] = "{\"string\"\n\n\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 3); + EXPECT_EQ(col, 0); +} + +TEST(CursorStreamWrapper, MissingSecondQuotes) { + const char json[] = "{\"string\"\n\n:my string\",\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 3); + EXPECT_EQ(col, 1); +} + +TEST(CursorStreamWrapper, MissingComma) { + const char json[] = "{\"string\"\n\n:\"my string\"\"array\"\n:[\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 3); + EXPECT_EQ(col, 12); +} + +TEST(CursorStreamWrapper, MissingArrayBracket) { + const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:\"1\", \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 4); + EXPECT_EQ(col, 9); +} + +TEST(CursorStreamWrapper, MissingArrayComma) { + const char json[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\" \"2\", \"3\"]}"; + size_t col, line; + bool ret = testJson(json, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 4); + EXPECT_EQ(col, 6); +} + +TEST(CursorStreamWrapper, MissingLastArrayBracket) { + const char json8[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"}"; + size_t col, line; + bool ret = testJson(json8, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 4); + EXPECT_EQ(col, 15); +} + +TEST(CursorStreamWrapper, MissingLastBracket) { + const char json9[] = "{\"string\"\n\n:\"my string\",\"array\"\n:[\"1\", \"2\", \"3\"]"; + size_t col, line; + bool ret = testJson(json9, line, col); + EXPECT_TRUE(ret); + EXPECT_EQ(line, 4); + EXPECT_EQ(col, 16); +} From 9394b84440fcbf4c2db80049e46c36a78bda04b8 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Fri, 29 Sep 2017 18:19:41 +0800 Subject: [PATCH 066/128] remove unnecessary code --- include/rapidjson/stream.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/include/rapidjson/stream.h b/include/rapidjson/stream.h index f492797..7f2643e 100644 --- a/include/rapidjson/stream.h +++ b/include/rapidjson/stream.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "rapidjson.h" @@ -104,7 +104,7 @@ inline void PutN(Stream& stream, Ch c, size_t n) { // GenericStreamWrapper //! A Stream Wrapper -/*! \tThis string stream is a wrapper for any stream by just forwarding any +/*! \tThis string stream is a wrapper for any stream by just forwarding any \treceived message to the origin stream. \note implements Stream concept */ @@ -119,10 +119,8 @@ template > class GenericStreamWrapper { public: typedef typename Encoding::Ch Ch; - size_t line_; - size_t col_; GenericStreamWrapper(InputStream& is): is_(is) {} - + Ch Peek() const { return is_.Peek(); } Ch Take() { return is_.Take(); } size_t Tell() { return is_.Tell(); } @@ -130,10 +128,10 @@ public: void Put(Ch ch) { is_.Put(ch); } void Flush() { is_.Flush(); } size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } - + // wrapper for MemoryStream const Ch* Peek4() const { return is_.Peek4(); } - + // wrapper for AutoUTFInputStream UTFType GetType() const { return is_.GetType(); } bool HasBOM() const { return is_.HasBOM(); } From 473553bd5ae255217d4176666bff604faa464826 Mon Sep 17 00:00:00 2001 From: KaitoHH Date: Fri, 29 Sep 2017 19:13:29 +0800 Subject: [PATCH 067/128] fix gcc & cl warning --- include/rapidjson/cursorstreamwrapper.h | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/cursorstreamwrapper.h b/include/rapidjson/cursorstreamwrapper.h index 5c752af..52c11a7 100644 --- a/include/rapidjson/cursorstreamwrapper.h +++ b/include/rapidjson/cursorstreamwrapper.h @@ -17,6 +17,17 @@ #include "stream.h" +#if defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + RAPIDJSON_NAMESPACE_BEGIN @@ -29,9 +40,9 @@ class CursorStreamWrapper : public GenericStreamWrapper { public: typedef typename Encoding::Ch Ch; - CursorStreamWrapper(InputStream& is): + CursorStreamWrapper(InputStream& is): GenericStreamWrapper(is), line_(1), col_(0) {} - + // counting line and column number Ch Take() { Ch ch = this->is_.Take(); @@ -54,6 +65,14 @@ private: size_t col_; //!< Current Column }; +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +#if defined(__GNUC__) +RAPIDJSON_DIAG_POP +#endif + RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ From 1f75402704a56532332a6b7e09e3f0ea85f02503 Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Sat, 30 Sep 2017 19:05:25 +0700 Subject: [PATCH 068/128] refactor Schema: Keep ErrorHandler reference in Context --- include/rapidjson/schema.h | 200 +++++++++++++++++++------------------ 1 file changed, 102 insertions(+), 98 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 53062eb..b4d1a26 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -318,6 +318,7 @@ template struct SchemaValidationContext { typedef Schema SchemaType; typedef ISchemaStateFactory SchemaValidatorFactoryType; + typedef IValidationErrorHandler ErrorHandlerType; typedef typename SchemaType::ValueType ValueType; typedef typename ValueType::Ch Ch; @@ -327,8 +328,9 @@ struct SchemaValidationContext { kPatternValidatorWithAdditionalProperty }; - SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) : + SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) : factory(f), + error_handler(eh), schema(s), valueSchema(), invalidKeyword(), @@ -368,6 +370,7 @@ struct SchemaValidationContext { } SchemaValidatorFactoryType& factory; + ErrorHandlerType& error_handler; const SchemaType* schema; const SchemaType* valueSchema; const Ch* invalidKeyword; @@ -664,7 +667,7 @@ public: return pointer_; } - bool BeginValue(Context& context, ErrorHandler& eh) const { + bool BeginValue(Context& context) const { if (context.inArray) { if (uniqueItems_) context.valueUniqueness = true; @@ -679,7 +682,7 @@ public: else if (additionalItems_) context.valueSchema = typeless_; else { - eh.DisallowedItem(context.arrayElementIndex); + context.error_handler.DisallowedItem(context.arrayElementIndex); RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); } } @@ -691,7 +694,7 @@ public: return true; } - RAPIDJSON_FORCEINLINE bool EndValue(Context& context, ErrorHandler& eh) const { + RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { if (context.patternPropertiesValidatorCount > 0) { bool otherValid = false; SizeType count = context.patternPropertiesValidatorCount; @@ -707,18 +710,18 @@ public: if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { if (!patternValid) { - eh.PropertyViolations(context.patternPropertiesValidators, count); + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } } else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { if (!patternValid || !otherValid) { - eh.PropertyViolations(context.patternPropertiesValidators, count + 1); + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } } else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) - eh.PropertyViolations(context.patternPropertiesValidators, count + 1); + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } } @@ -728,7 +731,7 @@ public: for (SizeType i = 0; i < enumCount_; i++) if (enum_[i] == h) goto foundEnum; - eh.DisallowedValue(); + context.error_handler.DisallowedValue(); RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); foundEnum:; } @@ -736,7 +739,7 @@ public: if (allOf_.schemas) for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) if (!context.validators[i]->IsValid()) { - eh.NotAllOf(&context.validators[allOf_.begin], allOf_.count); + context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); } @@ -744,7 +747,7 @@ public: for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) if (context.validators[i]->IsValid()) goto foundAny; - eh.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); + context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); foundAny:; } @@ -754,86 +757,86 @@ public: for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) if (context.validators[i]->IsValid()) { if (oneValid) { - eh.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); } else oneValid = true; } if (!oneValid) { - eh.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); } } if (not_ && context.validators[notValidatorIndex_]->IsValid()) { - eh.Disallowed(); + context.error_handler.Disallowed(); RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); } return true; } - bool Null(Context& context, ErrorHandler& eh) const { + bool Null(Context& context) const { if (!(type_ & (1 << kNullSchemaType))) { - DisallowedType(eh, GetNullString()); + DisallowedType(context, GetNullString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); } return CreateParallelValidator(context); } - bool Bool(Context& context, ErrorHandler& eh, bool) const { + bool Bool(Context& context, bool) const { if (!(type_ & (1 << kBooleanSchemaType))) { - DisallowedType(eh, GetBooleanString()); + DisallowedType(context, GetBooleanString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); } return CreateParallelValidator(context); } - bool Int(Context& context, ErrorHandler& eh, int i) const { - if (!CheckInt(context, eh, i)) + bool Int(Context& context, int i) const { + if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } - bool Uint(Context& context, ErrorHandler& eh, unsigned u) const { - if (!CheckUint(context, eh, u)) + bool Uint(Context& context, unsigned u) const { + if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } - bool Int64(Context& context, ErrorHandler& eh, int64_t i) const { - if (!CheckInt(context, eh, i)) + bool Int64(Context& context, int64_t i) const { + if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } - bool Uint64(Context& context, ErrorHandler& eh, uint64_t u) const { - if (!CheckUint(context, eh, u)) + bool Uint64(Context& context, uint64_t u) const { + if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } - bool Double(Context& context, ErrorHandler& eh, double d) const { + bool Double(Context& context, double d) const { if (!(type_ & (1 << kNumberSchemaType))) { - DisallowedType(eh, GetNumberString()); + DisallowedType(context, GetNumberString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); } - if (!minimum_.IsNull() && !CheckDoubleMinimum(context, eh, d)) + if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) return false; - if (!maximum_.IsNull() && !CheckDoubleMaximum(context, eh, d)) + if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) return false; - if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, eh, d)) + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) return false; return CreateParallelValidator(context); } - bool String(Context& context, ErrorHandler& eh, const Ch* str, SizeType length, bool) const { + bool String(Context& context, const Ch* str, SizeType length, bool) const { if (!(type_ & (1 << kStringSchemaType))) { - DisallowedType(eh, GetStringString()); + DisallowedType(context, GetStringString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); } @@ -841,27 +844,27 @@ public: SizeType count; if (internal::CountStringCodePoint(str, length, &count)) { if (count < minLength_) { - eh.TooShort(str, length, minLength_); + context.error_handler.TooShort(str, length, minLength_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); } if (count > maxLength_) { - eh.TooLong(str, length, maxLength_); + context.error_handler.TooLong(str, length, maxLength_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); } } } if (pattern_ && !IsPatternMatch(pattern_, str, length)) { - eh.DoesNotMatch(str, length); + context.error_handler.DoesNotMatch(str, length); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); } return CreateParallelValidator(context); } - bool StartObject(Context& context, ErrorHandler& eh) const { + bool StartObject(Context& context) const { if (!(type_ & (1 << kObjectSchemaType))) { - DisallowedType(eh, GetObjectString()); + DisallowedType(context, GetObjectString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); } @@ -880,7 +883,7 @@ public: return CreateParallelValidator(context); } - bool Key(Context& context, ErrorHandler& eh, const Ch* str, SizeType len, bool) const { + bool Key(Context& context, const Ch* str, SizeType len, bool) const { if (patternProperties_) { context.patternPropertiesSchemaCount = 0; for (SizeType i = 0; i < patternPropertyCount_; i++) @@ -922,62 +925,62 @@ public: } if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties - eh.DisallowedProperty(str, len); + context.error_handler.DisallowedProperty(str, len); RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); } return true; } - bool EndObject(Context& context, ErrorHandler& eh, SizeType memberCount) const { + bool EndObject(Context& context, SizeType memberCount) const { if (hasRequired_) { - eh.StartMissingProperties(); + context.error_handler.StartMissingProperties(); for (SizeType index = 0; index < propertyCount_; index++) if (properties_[index].required && !context.propertyExist[index]) - eh.AddMissingProperty(properties_[index].name); - if (eh.EndMissingProperties()) + context.error_handler.AddMissingProperty(properties_[index].name); + if (context.error_handler.EndMissingProperties()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); } if (memberCount < minProperties_) { - eh.TooFewProperties(memberCount, minProperties_); + context.error_handler.TooFewProperties(memberCount, minProperties_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); } if (memberCount > maxProperties_) { - eh.TooManyProperties(memberCount, maxProperties_); + context.error_handler.TooManyProperties(memberCount, maxProperties_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); } if (hasDependencies_) { - eh.StartDependencyErrors(); + context.error_handler.StartDependencyErrors(); for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { const Property& source = properties_[sourceIndex]; if (context.propertyExist[sourceIndex]) { if (source.dependencies) { - eh.StartMissingDependentProperties(); + context.error_handler.StartMissingDependentProperties(); for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) - eh.AddMissingDependentProperty(properties_[targetIndex].name); - eh.EndMissingDependentProperties(source.name); + context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name); + context.error_handler.EndMissingDependentProperties(source.name); } else if (source.dependenciesSchema) { ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex]; if (!dependenciesValidator->IsValid()) - eh.AddDependencySchemaError(source.name, dependenciesValidator); + context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator); } } } - if (eh.EndDependencyErrors()) + if (context.error_handler.EndDependencyErrors()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); } return true; } - bool StartArray(Context& context, ErrorHandler& eh) const { + bool StartArray(Context& context) const { if (!(type_ & (1 << kArraySchemaType))) { - DisallowedType(eh, GetArrayString()); + DisallowedType(context, GetArrayString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); } @@ -987,16 +990,16 @@ public: return CreateParallelValidator(context); } - bool EndArray(Context& context, ErrorHandler& eh, SizeType elementCount) const { + bool EndArray(Context& context, SizeType elementCount) const { context.inArray = false; if (elementCount < minItems_) { - eh.TooFewItems(elementCount, minItems_); + context.error_handler.TooFewItems(elementCount, minItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); } if (elementCount > maxItems_) { - eh.TooManyItems(elementCount, maxItems_); + context.error_handler.TooManyItems(elementCount, maxItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); } @@ -1218,130 +1221,131 @@ private: return false; } - bool CheckInt(Context& context, ErrorHandler& eh, int64_t i) const { + bool CheckInt(Context& context, int64_t i) const { if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { - DisallowedType(eh, GetIntegerString()); + DisallowedType(context, GetIntegerString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); } if (!minimum_.IsNull()) { if (minimum_.IsInt64()) { if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) { - eh.BelowMinimum(i, minimum_, exclusiveMinimum_); + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); } } else if (minimum_.IsUint64()) { - eh.BelowMinimum(i, minimum_, exclusiveMinimum_); + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() } - else if (!CheckDoubleMinimum(context, eh, static_cast(i))) + else if (!CheckDoubleMinimum(context, static_cast(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsInt64()) { if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { - eh.AboveMaximum(i, maximum_, exclusiveMaximum_); + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); } } else if (maximum_.IsUint64()) { } /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() - else if (!CheckDoubleMaximum(context, eh, static_cast(i))) + else if (!CheckDoubleMaximum(context, static_cast(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) { - eh.NotMultipleOf(i, multipleOf_); + context.error_handler.NotMultipleOf(i, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); } } - else if (!CheckDoubleMultipleOf(context, eh, static_cast(i))) + else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; } return true; } - bool CheckUint(Context& context, ErrorHandler& eh, uint64_t i) const { + bool CheckUint(Context& context, uint64_t i) const { if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { - DisallowedType(eh, GetIntegerString()); + DisallowedType(context, GetIntegerString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); } if (!minimum_.IsNull()) { if (minimum_.IsUint64()) { if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) { - eh.BelowMinimum(i, minimum_, exclusiveMinimum_); + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); } } else if (minimum_.IsInt64()) /* do nothing */; // i >= 0 > minimum.Getint64() - else if (!CheckDoubleMinimum(context, eh, static_cast(i))) + else if (!CheckDoubleMinimum(context, static_cast(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsUint64()) { if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { - eh.AboveMaximum(i, maximum_, exclusiveMaximum_); + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); } } else if (maximum_.IsInt64()) { - eh.AboveMaximum(i, maximum_, exclusiveMaximum_); + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ } - else if (!CheckDoubleMaximum(context, eh, static_cast(i))) + else if (!CheckDoubleMaximum(context, static_cast(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { if (i % multipleOf_.GetUint64() != 0) { - eh.NotMultipleOf(i, multipleOf_); + context.error_handler.NotMultipleOf(i, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); } } - else if (!CheckDoubleMultipleOf(context, eh, static_cast(i))) + else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; } return true; } - bool CheckDoubleMinimum(Context& context, ErrorHandler& eh, double d) const { + bool CheckDoubleMinimum(Context& context, double d) const { if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { - eh.BelowMinimum(d, minimum_, exclusiveMinimum_); + context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); } return true; } - bool CheckDoubleMaximum(Context& context, ErrorHandler& eh, double d) const { + bool CheckDoubleMaximum(Context& context, double d) const { if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { - eh.AboveMaximum(d, maximum_, exclusiveMaximum_); + context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); } return true; } - bool CheckDoubleMultipleOf(Context& context, ErrorHandler& eh, double d) const { + bool CheckDoubleMultipleOf(Context& context, double d) const { double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); double q = std::floor(a / b); double r = a - q * b; if (r > 0.0) { - eh.NotMultipleOf(d, multipleOf_); + context.error_handler.NotMultipleOf(d, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); } return true; } - void DisallowedType(ErrorHandler& eh, const ValueType& actualType) const { + void DisallowedType(Context& context, const ValueType& actualType) const { + ErrorHandler& eh = context.error_handler; eh.StartDisallowedType(); if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString()); @@ -2076,20 +2080,20 @@ RAPIDJSON_MULTILINEMACRO_END RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) - bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext(), *this), ( )); } - bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), *this, b), (b)); } - bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), *this, i), (i)); } - bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), *this, u), (u)); } - bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), *this, i), (i)); } - bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), *this, u), (u)); } - bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), *this, d), (d)); } + bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); } + bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } + bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } + bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } + bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } + bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } + bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } bool RawNumber(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), *this, str, length, copy), (str, length, copy)); } + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool String(const Ch* str, SizeType length, bool copy) - { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), *this, str, length, copy), (str, length, copy)); } + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool StartObject() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext(), *this)); + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); return valid_ = !outputHandler_ || outputHandler_->StartObject(); } @@ -2097,7 +2101,7 @@ RAPIDJSON_MULTILINEMACRO_END bool Key(const Ch* str, SizeType len, bool copy) { if (!valid_) return false; AppendToken(str, len); - if (!CurrentSchema().Key(CurrentContext(), *this, str, len, copy)) return valid_ = false; + if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); } @@ -2105,12 +2109,12 @@ RAPIDJSON_MULTILINEMACRO_END bool EndObject(SizeType memberCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); - if (!CurrentSchema().EndObject(CurrentContext(), *this, memberCount)) return valid_ = false; + if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); } bool StartArray() { - RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext(), *this)); + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); return valid_ = !outputHandler_ || outputHandler_->StartArray(); } @@ -2118,7 +2122,7 @@ RAPIDJSON_MULTILINEMACRO_END bool EndArray(SizeType elementCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); - if (!CurrentSchema().EndArray(CurrentContext(), *this, elementCount)) return valid_ = false; + if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); } @@ -2212,7 +2216,7 @@ private: if (CurrentContext().inArray) internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); - if (!CurrentSchema().BeginValue(CurrentContext(), *this)) + if (!CurrentSchema().BeginValue(CurrentContext())) return false; SizeType count = CurrentContext().patternPropertiesSchemaCount; @@ -2237,7 +2241,7 @@ private: } bool EndValue() { - if (!CurrentSchema().EndValue(CurrentContext(), *this)) + if (!CurrentSchema().EndValue(CurrentContext())) return false; #if RAPIDJSON_SCHEMA_VERBOSE @@ -2292,7 +2296,7 @@ private: } } - RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, &schema); } + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, *this, &schema); } RAPIDJSON_FORCEINLINE void PopSchema() { Context* c = schemaStack_.template Pop(1); From 8353e868d52edf825e4343f7afcbe263f1a24737 Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Sat, 30 Sep 2017 19:44:54 +0700 Subject: [PATCH 069/128] Move schema violation docs into Schema chapter --- doc/Doxyfile.in | 1 - doc/schema-errors.md | 269 ---------------------------------------- doc/schema.md | 286 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 277 insertions(+), 279 deletions(-) delete mode 100644 doc/schema-errors.md diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 4f23a79..ca14233 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -776,7 +776,6 @@ INPUT = readme.md \ doc/dom.md \ doc/sax.md \ doc/schema.md \ - doc/schema-errors.md \ doc/performance.md \ doc/internals.md \ doc/faq.md diff --git a/doc/schema-errors.md b/doc/schema-errors.md deleted file mode 100644 index f82120e..0000000 --- a/doc/schema-errors.md +++ /dev/null @@ -1,269 +0,0 @@ -# Schema violation reporting - -(Unreleased as of 2017-09-20) - -When validating an instance against a JSON Schema, -it is often desirable to report not only whether the instance is valid, -but also the ways in which it violates the schema. - -The `SchemaValidator` class -collects errors encountered during validation -into a JSON `Value`. -This error object can then be accessed as `validator.GetError()`. - -The structure of the error object is subject to change -in future versions of RapidJSON, -as there is no standard schema for violations. -The details below this point are provisional only. - -[TOC] - -# General provisions {#General} - -Validation of an instance value against a schema -produces an error value. -The error value is always an object. -An empty object `{}` indicates the instance is valid. - -* The name of each member - corresponds to the JSON Schema keyword that is violated. -* The value is either an object describing a single violation, - or an array of such objects. - -Each violation object contains two string-valued members -named `instanceRef` and `schemaRef`. -`instanceRef` contains the URI fragment serialization -of a JSON Pointer to the instance subobject -in which the violation was detected. -`schemaRef` contains the URI of the schema -and the fragment serialization of a JSON Pointer -to the subschema that was violated. - -Individual violation objects can contain other keyword-specific members. -These are detailed further. - -For example, validating this instance: - -~~~json -{"numbers": [1, 2, "3", 4, 5]} -~~~ - -against this schema: - -~~~json -{ - "type": "object", - "properties": { - "numbers": {"$ref": "numbers.schema.json"} - } -} -~~~ - -where `numbers.schema.json` refers -(via a suitable `IRemoteSchemaDocumentProvider`) -to this schema: - -~~~json -{ - "type": "array", - "items": {"type": "number"} -} -~~~ - -produces the following error object: - -~~~json -{ - "type": { - "instanceRef": "#/numbers/2", - "schemaRef": "numbers.schema.json#/items", - "expected": ["number"], - "actual": "string" - } -} -~~~ - -# Validation keywords for numbers {#numbers} - -## multipleOf {#multipleOf} - -* `expected`: required number strictly greater than 0. - The value of the `multipleOf` keyword specified in the schema. -* `actual`: required number. - The instance value. - -## maximum {#maximum} - -* `expected`: required number. - The value of the `maximum` keyword specified in the schema. -* `exclusiveMaximum`: optional boolean. - This will be true if the schema specified `"exclusiveMaximum": true`, - and will be omitted otherwise. -* `actual`: required number. - The instance value. - -## minimum {#minimum} - -* `expected`: required number. - The value of the `minimum` keyword specified in the schema. -* `exclusiveMinimum`: optional boolean. - This will be true if the schema specified `"exclusiveMinimum": true`, - and will be omitted otherwise. -* `actual`: required number. - The instance value. - -# Validation keywords for strings {#strings} - -## maxLength {#maxLength} - -* `expected`: required number greater than or equal to 0. - The value of the `maxLength` keyword specified in the schema. -* `actual`: required string. - The instance value. - -## minLength {#minLength} - -* `expected`: required number greater than or equal to 0. - The value of the `minLength` keyword specified in the schema. -* `actual`: required string. - The instance value. - -## pattern {#pattern} - -* `actual`: required string. - The instance value. - -(The expected pattern is not reported -because the internal representation in `SchemaDocument` -does not store the pattern in original string form.) - -# Validation keywords for arrays {#arrays} - -## additionalItems {#additionalItems} - -This keyword is reported -when the value of `items` schema keyword is an array, -the value of `additionalItems` is `false`, -and the instance is an array -with more items than specified in the `items` array. - -* `disallowed`: required integer greater than or equal to 0. - The index of the first item that has no corresponding schema. - -## maxItems and minItems {#maxItems} - -* `expected`: required integer greater than or equal to 0. - The value of `maxItems` (respectively, `minItems`) - specified in the schema. -* `actual`: required integer greater than or equal to 0. - Number of items in the instance array. - -## uniqueItems {#uniqueItems} - -* `duplicates`: required array - whose items are integers greater than or equal to 0. - Indices of items of the instance that are equal. - -(RapidJSON only reports the first two equal items, -for performance reasons.) - -# Validation keywords for objects - -## maxProperties and minProperties {#maxProperties} - -* `expected`: required integer greater than or equal to 0. - The value of `maxProperties` (respectively, `minProperties`) - specified in the schema. -* `actual`: required integer greater than or equal to 0. - Number of properties in the instance object. - -## required {#required} - -* `missing`: required array of one or more unique strings. - The names of properties - that are listed in the value of the `required` schema keyword - but not present in the instance object. - -## additionalProperties {#additionalProperties} - -This keyword is reported -when the schema specifies `additionalProperties: false` -and the name of a property of the instance is -neither listed in the `properties` keyword -nor matches any regular expression in the `patternProperties` keyword. - -* `disallowed`: required string. - Name of the offending property of the instance. - -(For performance reasons, -RapidJSON only reports the first such property encountered.) - -## dependencies {#dependencies} - -* `errors`: required object with one or more properties. - Names and values of its properties are described below. - -Recall that JSON Schema Draft 04 supports -*schema dependencies*, -where presence of a named *controlling* property -requires the instance object to be valid against a subschema, -and *property dependencies*, -where presence of a controlling property -requires other *dependent* properties to be also present. - -For a violated schema dependency, -`errors` will contain a property -with the name of the controlling property -and its value will be the error object -produced by validating the instance object -against the dependent schema. - -For a violated property dependency, -`errors` will contain a property -with the name of the controlling property -and its value will be an array of one or more unique strings -listing the missing dependent properties. - -# Validation keywords for any instance type {#anytypes} - -## enum {#enum} - -This keyword has no additional properties -beyond `instanceRef` and `schemaRef`. - -* The allowed values are not listed - because `SchemaDocument` does not store them in original form. -* The violating value is not reported - because it might be unwieldy. - -If you need to report these details to your users, -you can access the necessary information -by following `instanceRef` and `schemaRef`. - -## type {#type} - -* `expected`: required array of one or more unique strings, - each of which is one of the seven primitive types - defined by the JSON Schema Draft 04 Core specification. - Lists the types allowed by the `type` schema keyword. -* `actual`: required string, also one of seven primitive types. - The primitive type of the instance. - -## allOf, anyOf, and oneOf {#allOf} - -* `errors`: required array of at least one object. - There will be as many items as there are subschemas - in the `allOf`, `anyOf` or `oneOf` schema keyword, respectively. - Each item will be the error value - produced by validating the instance - against the corresponding subschema. - -For `allOf`, at least one error value will be non-empty. -For `anyOf`, all error values will be non-empty. -For `oneOf`, either all error values will be non-empty, -or more than one will be empty. - -## not {#not} - -This keyword has no additional properties -apart from `instanceRef` and `schemaRef`. diff --git a/doc/schema.md b/doc/schema.md index 29ba4f5..9d1b21a 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http:// [TOC] -## Basic Usage +# Basic Usage {#Basic} First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`. @@ -52,11 +52,11 @@ Some notes: * One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. * A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first. -## Validation during parsing/serialization +# Validation during parsing/serialization {#Fused} Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. -### DOM parsing +## DOM parsing {#DOM} For using DOM in parsing, `Document` needs some preparation and finalizing tasks, in addition to receiving SAX events, thus it needs some work to route the reader, validator and the document. `SchemaValidatingReader` is a helper class that doing such work. @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -### SAX parsing +## SAX parsing {#SAX} For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -### Serialization +## Serialization {#Serialization} It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema. @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { Of course, if your application only needs SAX-style serialization, it can simply send SAX events to `SchemaValidator` instead of `Writer`. -## Remote Schema +# Remote Schema {#Remote} JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](doc/pointer.md) referencing to a local or remote schema. Local pointer is prefixed with `#`, while remote pointer is an relative or absolute URI. For example: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -## Conformance +# Conformance {#Conformance} RapidJSON passed 262 out of 263 tests in [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4). @@ -176,7 +176,7 @@ The failed test is "changed scope ref invalid" of "change resolution scope" in ` Besides, the `format` schema keyword for string values is ignored, since it is not required by the specification. -### Regular Expression +## Regular Expression {#Regex} The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern. @@ -211,7 +211,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d For C++11 compiler, it is also possible to use the `std::regex` by defining `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. If your schemas do not need `pattern` and `patternProperties`, you can set both macros to zero to disable this feature, which will reduce some code size. -## Performance +# Performance {#Performance} Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. @@ -235,3 +235,271 @@ On a Mac Book Pro (2.8 GHz Intel Core i7), the following results are collected. |[`jayschema`](https://github.com/natesilva/jayschema)|0.1%|21 (± 1.14%)| That is, RapidJSON is about 1.5x faster than the fastest JavaScript library (ajv). And 1400x faster than the slowest one. + +# Schema violation reporting {#Reporting} + +(Unreleased as of 2017-09-20) + +When validating an instance against a JSON Schema, +it is often desirable to report not only whether the instance is valid, +but also the ways in which it violates the schema. + +The `SchemaValidator` class +collects errors encountered during validation +into a JSON `Value`. +This error object can then be accessed as `validator.GetError()`. + +The structure of the error object is subject to change +in future versions of RapidJSON, +as there is no standard schema for violations. +The details below this point are provisional only. + +## General provisions {#ReportingGeneral} + +Validation of an instance value against a schema +produces an error value. +The error value is always an object. +An empty object `{}` indicates the instance is valid. + +* The name of each member + corresponds to the JSON Schema keyword that is violated. +* The value is either an object describing a single violation, + or an array of such objects. + +Each violation object contains two string-valued members +named `instanceRef` and `schemaRef`. +`instanceRef` contains the URI fragment serialization +of a JSON Pointer to the instance subobject +in which the violation was detected. +`schemaRef` contains the URI of the schema +and the fragment serialization of a JSON Pointer +to the subschema that was violated. + +Individual violation objects can contain other keyword-specific members. +These are detailed further. + +For example, validating this instance: + +~~~json +{"numbers": [1, 2, "3", 4, 5]} +~~~ + +against this schema: + +~~~json +{ + "type": "object", + "properties": { + "numbers": {"$ref": "numbers.schema.json"} + } +} +~~~ + +where `numbers.schema.json` refers +(via a suitable `IRemoteSchemaDocumentProvider`) +to this schema: + +~~~json +{ + "type": "array", + "items": {"type": "number"} +} +~~~ + +produces the following error object: + +~~~json +{ + "type": { + "instanceRef": "#/numbers/2", + "schemaRef": "numbers.schema.json#/items", + "expected": ["number"], + "actual": "string" + } +} +~~~ + +## Validation keywords for numbers {#Numbers} + +### multipleOf {#multipleof} + +* `expected`: required number strictly greater than 0. + The value of the `multipleOf` keyword specified in the schema. +* `actual`: required number. + The instance value. + +### maximum {#maximum} + +* `expected`: required number. + The value of the `maximum` keyword specified in the schema. +* `exclusiveMaximum`: optional boolean. + This will be true if the schema specified `"exclusiveMaximum": true`, + and will be omitted otherwise. +* `actual`: required number. + The instance value. + +### minimum {#minimum} + +* `expected`: required number. + The value of the `minimum` keyword specified in the schema. +* `exclusiveMinimum`: optional boolean. + This will be true if the schema specified `"exclusiveMinimum": true`, + and will be omitted otherwise. +* `actual`: required number. + The instance value. + +## Validation keywords for strings {#Strings} + +### maxLength {#maxLength} + +* `expected`: required number greater than or equal to 0. + The value of the `maxLength` keyword specified in the schema. +* `actual`: required string. + The instance value. + +### minLength {#minLength} + +* `expected`: required number greater than or equal to 0. + The value of the `minLength` keyword specified in the schema. +* `actual`: required string. + The instance value. + +### pattern {#pattern} + +* `actual`: required string. + The instance value. + +(The expected pattern is not reported +because the internal representation in `SchemaDocument` +does not store the pattern in original string form.) + +## Validation keywords for arrays {#Arrays} + +### additionalItems {#additionalItems} + +This keyword is reported +when the value of `items` schema keyword is an array, +the value of `additionalItems` is `false`, +and the instance is an array +with more items than specified in the `items` array. + +* `disallowed`: required integer greater than or equal to 0. + The index of the first item that has no corresponding schema. + +### maxItems and minItems {#maxItems-minItems} + +* `expected`: required integer greater than or equal to 0. + The value of `maxItems` (respectively, `minItems`) + specified in the schema. +* `actual`: required integer greater than or equal to 0. + Number of items in the instance array. + +### uniqueItems {#uniqueItems} + +* `duplicates`: required array + whose items are integers greater than or equal to 0. + Indices of items of the instance that are equal. + +(RapidJSON only reports the first two equal items, +for performance reasons.) + +## Validation keywords for objects + +### maxProperties and minProperties {#maxProperties-minProperties} + +* `expected`: required integer greater than or equal to 0. + The value of `maxProperties` (respectively, `minProperties`) + specified in the schema. +* `actual`: required integer greater than or equal to 0. + Number of properties in the instance object. + +### required {#required} + +* `missing`: required array of one or more unique strings. + The names of properties + that are listed in the value of the `required` schema keyword + but not present in the instance object. + +### additionalProperties {#additionalProperties} + +This keyword is reported +when the schema specifies `additionalProperties: false` +and the name of a property of the instance is +neither listed in the `properties` keyword +nor matches any regular expression in the `patternProperties` keyword. + +* `disallowed`: required string. + Name of the offending property of the instance. + +(For performance reasons, +RapidJSON only reports the first such property encountered.) + +### dependencies {#dependencies} + +* `errors`: required object with one or more properties. + Names and values of its properties are described below. + +Recall that JSON Schema Draft 04 supports +*schema dependencies*, +where presence of a named *controlling* property +requires the instance object to be valid against a subschema, +and *property dependencies*, +where presence of a controlling property +requires other *dependent* properties to be also present. + +For a violated schema dependency, +`errors` will contain a property +with the name of the controlling property +and its value will be the error object +produced by validating the instance object +against the dependent schema. + +For a violated property dependency, +`errors` will contain a property +with the name of the controlling property +and its value will be an array of one or more unique strings +listing the missing dependent properties. + +## Validation keywords for any instance type {#AnyTypes} + +### enum {#enum} + +This keyword has no additional properties +beyond `instanceRef` and `schemaRef`. + +* The allowed values are not listed + because `SchemaDocument` does not store them in original form. +* The violating value is not reported + because it might be unwieldy. + +If you need to report these details to your users, +you can access the necessary information +by following `instanceRef` and `schemaRef`. + +### type {#type} + +* `expected`: required array of one or more unique strings, + each of which is one of the seven primitive types + defined by the JSON Schema Draft 04 Core specification. + Lists the types allowed by the `type` schema keyword. +* `actual`: required string, also one of seven primitive types. + The primitive type of the instance. + +### allOf, anyOf, and oneOf {#allOf-anyOf-oneOf} + +* `errors`: required array of at least one object. + There will be as many items as there are subschemas + in the `allOf`, `anyOf` or `oneOf` schema keyword, respectively. + Each item will be the error value + produced by validating the instance + against the corresponding subschema. + +For `allOf`, at least one error value will be non-empty. +For `anyOf`, all error values will be non-empty. +For `oneOf`, either all error values will be non-empty, +or more than one will be empty. + +### not {#not} + +This keyword has no additional properties +apart from `instanceRef` and `schemaRef`. From 8c182e51e76dced3cc998f3c37812118c9653231 Mon Sep 17 00:00:00 2001 From: Yuri Khan Date: Sat, 30 Sep 2017 20:16:03 +0700 Subject: [PATCH 070/128] Flatten allOf keyword violations --- include/rapidjson/schema.h | 4 +- test/unittest/schematest.cpp | 148 +++++++++++------------------------ 2 files changed, 49 insertions(+), 103 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index b4d1a26..e7c87f6 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -2011,7 +2011,9 @@ public: AddCurrentError(SchemaType::GetTypeString()); } void NotAllOf(ISchemaValidator** subvalidators, SizeType count) { - AddErrorArray(SchemaType::GetAllOfString(), subvalidators, count); + for (SizeType i = 0; i < count; ++i) { + MergeError(static_cast(subvalidators[i])->GetError()); + } } void NoneOf(ISchemaValidator** subvalidators, SizeType count) { AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count); diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 5bf39f8..121d386 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -236,15 +236,9 @@ TEST(SchemaValidator, AllOf) { VALIDATE(s, "\"ok\"", true); INVALIDATE(s, "\"too long\"", "", "allOf", "", - "{ \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," - " \"errors\": [" - " {}," - " { \"maxLength\": { " - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\", " - " \"expected\": 5, \"actual\": \"too long\"" - " }}" - " ]" + "{ \"maxLength\": { " + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\", " + " \"expected\": 5, \"actual\": \"too long\"" "}}"); } { @@ -254,14 +248,8 @@ TEST(SchemaValidator, AllOf) { VALIDATE(s, "\"No way\"", false); INVALIDATE(s, "-1", "", "allOf", "", - "{ \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," - " \"errors\": [" - " { \"type\": { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," - " \"expected\": [\"string\"], \"actual\": \"integer\"" - " }}," - " {}" - " ]" + "{ \"type\": { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" "}}"); } } @@ -387,16 +375,11 @@ TEST(SchemaValidator, Ref_AllOf) { SchemaDocument s(sd); INVALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\"} }", "/properties/shipping_address", "allOf", "/shipping_address", - "{ \"allOf\": {" + "{ \"required\": {" " \"instanceRef\": \"#/shipping_address\"," - " \"schemaRef\": \"#/properties/shipping_address\"," - " \"errors\": [" - " {}," - " { \"required\": {" - " \"instanceRef\": \"#/shipping_address\"," - " \"schemaRef\": \"#/properties/shipping_address/allOf/1\"," - " \"missing\": [\"type\"]" - "}} ] }}"); + " \"schemaRef\": \"#/properties/shipping_address/allOf/1\"," + " \"missing\": [\"type\"]" + "}}"); VALIDATE(s, "{\"shipping_address\": {\"street_address\": \"1600 Pennsylvania Avenue NW\", \"city\": \"Washington\", \"state\": \"DC\", \"type\": \"business\"} }", true); } @@ -1537,87 +1520,48 @@ TEST(SchemaValidator, AllOf_Nested) { VALIDATE(s, "\"ok\"", true); VALIDATE(s, "\"OK\"", true); INVALIDATE(s, "\"okay\"", "", "allOf", "", - "{ \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," - " \"errors\": [" - " {}, " - " {}, " - " { \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\"," - " \"errors\": [" - " {}, " - " { \"enum\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"" - "}} ] }} ] }}"); + "{ \"enum\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"" + "}}"); INVALIDATE(s, "\"o\"", "", "allOf", "", - "{ \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," - " \"errors\": [" - " { \"minLength\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," - " \"expected\": 2, \"actual\": \"o\"" - " }}," - " {}," - " {}" - " ]" + "{ \"minLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," + " \"expected\": 2, \"actual\": \"o\"" "}}"); INVALIDATE(s, "\"n\"", "", "allOf", "", - "{ \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," - " \"errors\": [" - " { \"minLength\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," - " \"expected\": 2, \"actual\": \"n\"" - " }}," - " {}, " - " { \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\"," - " \"errors\": [" - " { \"enum\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"" - " }}," - " { \"enum\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"" - "}} ] }} ] }}"); + "{ \"minLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," + " \"expected\": 2, \"actual\": \"n\"" + " }," + " \"enum\": [" + " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}," + " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}" + " ]" + "}") INVALIDATE(s, "\"too long\"", "", "allOf", "", - "{ \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," - " \"errors\": [" - " {}, " - " { \"maxLength\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\"," - " \"expected\": 5, \"actual\": \"too long\"" - " }}," - " { \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\"," - " \"errors\": [" - " { \"enum\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"" - " }}," - " { \"enum\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"" - "}} ] }} ] }}"); + "{ \"maxLength\": {" + " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\"," + " \"expected\": 5, \"actual\": \"too long\"" + " }," + " \"enum\": [" + " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}," + " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}" + " ]" + "}"); INVALIDATE(s, "123", "", "allOf", "", - "{ \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#\"," - " \"errors\": [" - " { \"type\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," - " \"expected\": [\"string\"], \"actual\": \"integer\"" - " }}," - " { \"type\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\"," - " \"expected\": [\"string\"], \"actual\": \"integer\"" - " }}," - " { \"allOf\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2\"," - " \"errors\": [" - " { \"enum\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"" - " }}, " - " { \"enum\": {" - " \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"" - "}} ] }} ] }}"); + "{ \"type\": [" + " { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/0\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + " }," + " { \"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/1\"," + " \"expected\": [\"string\"], \"actual\": \"integer\"" + " }" + " ]," + " \"enum\": [" + " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/0\"}," + " {\"instanceRef\": \"#\", \"schemaRef\": \"#/allOf/2/allOf/1\"}" + " ]" + "}"); } TEST(SchemaValidator, EscapedPointer) { From 84ca485e51af4fec2ab121c7ddb597dd0f7b3c76 Mon Sep 17 00:00:00 2001 From: Captain Crutches Date: Mon, 2 Oct 2017 20:39:40 -0400 Subject: [PATCH 071/128] Make RapidJSON_INCLUDE_DIR non-blank in Config.cmake --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ccc374..ac1fc25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,6 +181,8 @@ EXPORT( PACKAGE ${PROJECT_NAME} ) # ... for the build tree SET( CONFIG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) SET( CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR}) +SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_CMAKE_DIR}/include" ) + CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in From f0391747e608555b3f70ae6b9c902c5082e80907 Mon Sep 17 00:00:00 2001 From: David Newman Date: Tue, 3 Oct 2017 23:26:19 -0400 Subject: [PATCH 072/128] chore: correct spelling --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index b833a98..78c9540 100644 --- a/readme.md +++ b/readme.md @@ -43,7 +43,7 @@ RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml]( More features can be read [here](doc/features.md). -JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at +JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in full compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at * [Introducing JSON](http://json.org/) * [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159) * [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm) From 6e08e2942509389dbeec137c6079c464b92ba646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Dupuis?= Date: Thu, 5 Oct 2017 11:39:21 +0200 Subject: [PATCH 073/128] Initialized regex with schema allocator. --- include/rapidjson/schema.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index abcf1a1..d884064 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -935,7 +935,7 @@ private: }; #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - typedef internal::GenericRegex RegexType; + typedef internal::GenericRegex RegexType; #elif RAPIDJSON_SCHEMA_USE_STDREGEX typedef std::basic_regex RegexType; #else @@ -995,7 +995,7 @@ private: template RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) { - RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); if (!r->IsValid()) { r->~RegexType(); AllocatorType::Free(r); From b217cc640c6afeadab23e30dbb588245a4cbfde3 Mon Sep 17 00:00:00 2001 From: piotr-kaminski-intel <32583365+piotr-kaminski-intel@users.noreply.github.com> Date: Sat, 7 Oct 2017 00:50:55 +0200 Subject: [PATCH 074/128] Removing Klocwork issues from schema.h Removing Klocwork static code analysis critical issues: line 358: 'this->notValidatorIndex_' might not be initialized in this constructor. line :412 Pointer 'schemaDocument' checked for NULL at line 412 may be passed to function and may be dereferenced there by passing argument this to function 'CreateSchema' at line 419. Also there are 7 similar errors on lines 467 479 511 523 533 538 549. --- include/rapidjson/schema.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index abcf1a1..2c5def1 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -355,6 +355,7 @@ public: not_(), type_((1 << kTotalSchemaType) - 1), // typeless validatorCount_(), + notValidatorIndex_(), properties_(), additionalPropertiesSchema_(), patternProperties_(), @@ -409,11 +410,9 @@ public: } } - if (schemaDocument) { - AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); - AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); - AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); - } + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); if (const ValueType* v = GetMember(value, GetNotString())) { schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); From f64b77300735c1648fc695ef5df321b693f4e14b Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 9 Oct 2017 11:33:48 +0800 Subject: [PATCH 075/128] Partially fix #1077 --- include/rapidjson/encodings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/encodings.h b/include/rapidjson/encodings.h index 0df1c34..7903e76 100644 --- a/include/rapidjson/encodings.h +++ b/include/rapidjson/encodings.h @@ -384,7 +384,7 @@ struct UTF16BE : UTF16 { static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(static_cast(is.Take())) << 8; - c |= static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())); return static_cast(c); } From 495266271fb12b6d3ed0a9cf3e251e8b240a6d87 Mon Sep 17 00:00:00 2001 From: Captain Crutches Date: Sun, 8 Oct 2017 23:43:18 -0400 Subject: [PATCH 076/128] Use SOURCE_DIR instead of CMAKE_DIR for build tree --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac1fc25..846828f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,7 +181,7 @@ EXPORT( PACKAGE ${PROJECT_NAME} ) # ... for the build tree SET( CONFIG_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) SET( CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR}) -SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_CMAKE_DIR}/include" ) +SET( ${PROJECT_NAME}_INCLUDE_DIR "\${${PROJECT_NAME}_SOURCE_DIR}/include" ) CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) From bb99ccb0309bb1cd5b3650af8ee6336325813040 Mon Sep 17 00:00:00 2001 From: piotr-kaminski-intel <32583365+piotr-kaminski-intel@users.noreply.github.com> Date: Tue, 10 Oct 2017 14:09:23 +0200 Subject: [PATCH 077/128] Init variable in the constructor line 358: 'this->notValidatorIndex_' might not be initialized in this constructor. --- include/rapidjson/schema.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 2c5def1..cbcb550 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -410,9 +410,11 @@ public: } } - AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); - AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); - AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + if (schemaDocument) { + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + } if (const ValueType* v = GetMember(value, GetNotString())) { schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); From 7bd9b5a1adeb24724ae1e0f1cf048d3f3ba09d85 Mon Sep 17 00:00:00 2001 From: "M.Tayel" <32839716+m-tayel@users.noreply.github.com> Date: Mon, 16 Oct 2017 15:01:27 +0200 Subject: [PATCH 078/128] enable cross compiling by adding option to remove -march/-cpu --- CMakeLists.txt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 846828f..950d115 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,8 @@ option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON) option(RAPIDJSON_BUILD_ASAN "Build rapidjson with address sanitizer (gcc/clang)" OFF) option(RAPIDJSON_BUILD_UBSAN "Build rapidjson with undefined behavior sanitizer (gcc/clang)" OFF) +option(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT "Build rapidjson with -march or -mcpu options" ON) + option(RAPIDJSON_HAS_STDSTRING "" OFF) if(RAPIDJSON_HAS_STDSTRING) add_definitions(-DRAPIDJSON_HAS_STDSTRING) @@ -50,11 +52,13 @@ if(CCACHE_FOUND) endif(CCACHE_FOUND) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") - else() - #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") + if(${RAPIDJSON_DISABLE_INSTRUMENTATION_OPT}) + if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") + else() + #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") + endif() endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror") set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wsign-conversion) From a8e99906039b62ababdab1e709f7e27ccccee5e0 Mon Sep 17 00:00:00 2001 From: h46incon Date: Thu, 19 Oct 2017 20:41:27 +0800 Subject: [PATCH 079/128] Add MemberCapacity() and MemberReserve() interface for object type. --- include/rapidjson/document.h | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 93b091f..094a07e 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1070,6 +1070,9 @@ public: //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + //! Get the capacity of object. + SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } + //! Check whether the object is empty. bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } @@ -1138,6 +1141,21 @@ public: /*! \pre IsObject() == true */ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } + //! Request the object to have enough capacity to store members. + /*! \param newCapacity The capacity that the object at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsObject()); + if (newCapacity > data_.o.capacity) { + SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); + data_.o.capacity = newCapacity; + } + return *this; + } + //! Check whether a member exists in the object. /*! \param name Member name to be searched. @@ -1243,17 +1261,8 @@ public: RAPIDJSON_ASSERT(name.IsString()); ObjectData& o = data_.o; - if (o.size >= o.capacity) { - if (o.capacity == 0) { - o.capacity = kDefaultObjectCapacity; - SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); - } - else { - SizeType oldCapacity = o.capacity; - o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 - SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); - } - } + if (o.size >= o.capacity) + MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator); Member* members = GetMembersPointer(); members[o.size].name.RawAssign(name); members[o.size].value.RawAssign(value); @@ -2548,6 +2557,7 @@ public: ~GenericObject() {} SizeType MemberCount() const { return value_.MemberCount(); } + SizeType MemberCapacity() const { return value_.MemberCapacity(); } bool ObjectEmpty() const { return value_.ObjectEmpty(); } template ValueType& operator[](T* name) const { return value_[name]; } template ValueType& operator[](const GenericValue& name) const { return value_[name]; } @@ -2556,6 +2566,7 @@ public: #endif MemberIterator MemberBegin() const { return value_.MemberBegin(); } MemberIterator MemberEnd() const { return value_.MemberEnd(); } + GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } bool HasMember(const Ch* name) const { return value_.HasMember(name); } #if RAPIDJSON_HAS_STDSTRING bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } From db305dcf217ea1dd009a1355835932de6d866cb5 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 20 Oct 2017 10:33:37 +0800 Subject: [PATCH 080/128] Fix schema.md TOC --- doc/schema.md | 18 +++++++++--------- doc/schema.zh-cn.md | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/doc/schema.md b/doc/schema.md index 29ba4f5..dc01626 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http:// [TOC] -## Basic Usage +# Basic Usage First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`. @@ -52,11 +52,11 @@ Some notes: * One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. * A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first. -## Validation during parsing/serialization +# Validation during parsing/serialization Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. -### DOM parsing +## DOM parsing For using DOM in parsing, `Document` needs some preparation and finalizing tasks, in addition to receiving SAX events, thus it needs some work to route the reader, validator and the document. `SchemaValidatingReader` is a helper class that doing such work. @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -### SAX parsing +## SAX parsing For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -### Serialization +## Serialization It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema. @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { Of course, if your application only needs SAX-style serialization, it can simply send SAX events to `SchemaValidator` instead of `Writer`. -## Remote Schema +# Remote Schema JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](doc/pointer.md) referencing to a local or remote schema. Local pointer is prefixed with `#`, while remote pointer is an relative or absolute URI. For example: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -## Conformance +# Conformance RapidJSON passed 262 out of 263 tests in [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4). @@ -176,7 +176,7 @@ The failed test is "changed scope ref invalid" of "change resolution scope" in ` Besides, the `format` schema keyword for string values is ignored, since it is not required by the specification. -### Regular Expression +## Regular Expression The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern. @@ -211,7 +211,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d For C++11 compiler, it is also possible to use the `std::regex` by defining `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. If your schemas do not need `pattern` and `patternProperties`, you can set both macros to zero to disable this feature, which will reduce some code size. -## Performance +# Performance Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. diff --git a/doc/schema.zh-cn.md b/doc/schema.zh-cn.md index 5df1f31..1dd7e79 100644 --- a/doc/schema.zh-cn.md +++ b/doc/schema.zh-cn.md @@ -8,7 +8,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document [TOC] -## 基本用法 +# 基本用法 首先,你要把 JSON Schema 解析成 `Document`,再把它编译成一个 `SchemaDocument`。 @@ -52,11 +52,11 @@ if (!d.Accept(validator)) { * 一个 `SchemaDocment` 能被多个 `SchemaValidator` 引用。它不会被 `SchemaValidator` 修改。 * 可以重复使用一个 `SchemaValidator` 来校验多个文件。在校验其他文件前,须先调用 `validator.Reset()`。 -## 在解析/生成时进行校验 +# 在解析/生成时进行校验 与大部分 JSON Schema 校验器有所不同,RapidJSON 提供了一个基于 SAX 的 schema 校验器实现。因此,你可以在输入流解析 JSON 的同时进行校验。若校验器遇到一个与 schema 不符的值,就会立即终止解析。这设计对于解析大型 JSON 文件时特别有用。 -### DOM 解析 +## DOM 解析 在使用 DOM 进行解析时,`Document` 除了接收 SAX 事件外,还需做一些准备及结束工作,因此,为了连接 `Reader`、`SchemaValidator` 和 `Document` 要做多一点事情。`SchemaValidatingReader` 是一个辅助类去做那些工作。 @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -### SAX 解析 +## SAX 解析 使用 SAX 解析时,情况就简单得多。若只需要校验 JSON 而无需进一步处理,那么仅需要: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -### 生成 +## 生成 我们也可以在生成(serialization)的时候进行校验。这能确保输出的 JSON 符合一个 JSON Schema。 @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { 当然,如果你的应用仅需要 SAX 风格的生成,那么只需要把 SAX 事件由原来发送到 `Writer`,改为发送到 `SchemaValidator`。 -## 远程 Schema +# 远程 Schema JSON Schema 支持 [`$ref` 关键字](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个 [JSON pointer](doc/pointer.zh-cn.md) 引用至一个本地(local)或远程(remote) schema。本地指针的首字符是 `#`,而远程指针是一个相对或绝对 URI。例如: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -## 标准的符合程度 +# 标准的符合程度 RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4) 中 263 个测试的 262 个。 @@ -176,7 +176,7 @@ RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON 除此以外,关于字符串类型的 `format` schema 关键字也会被忽略,因为标准中并没需求必须实现。 -### 正则表达式 +## 正则表达式 `pattern` 及 `patternProperties` 这两个 schema 关键字使用了正则表达式去匹配所需的模式。 @@ -211,7 +211,7 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用 对于使用 C++11 编译器的使用者,也可使用 `std::regex`,只需定义 `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` 及 `RAPIDJSON_SCHEMA_USE_STDREGEX=1`。若你的 schema 无需使用 `pattern` 或 `patternProperties`,可以把两个宏都设为零,以禁用此功能,这样做可节省一些代码体积。 -## 性能 +# 性能 大部分 C++ JSON 库都未支持 JSON Schema。因此我们尝试按照 [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) 去评估 RapidJSON 的 JSON Schema 校验器。该评测测试了 11 个运行在 node.js 上的 JavaScript 库。 From 3c07cecdb85aa3b3a680402bc7c4a19bb942185d Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 20 Oct 2017 11:16:44 +0800 Subject: [PATCH 081/128] Add anchors to Schema.md --- doc/schema.md | 18 +++++++++--------- doc/schema.zh-cn.md | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/doc/schema.md b/doc/schema.md index dc01626..5e396ce 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http:// [TOC] -# Basic Usage +# Basic Usage {#BasicUsage} First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`. @@ -52,11 +52,11 @@ Some notes: * One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. * A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first. -# Validation during parsing/serialization +# Validation during parsing/serialization {#ParsingSerialization} Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. -## DOM parsing +## DOM parsing {#DomParsing} For using DOM in parsing, `Document` needs some preparation and finalizing tasks, in addition to receiving SAX events, thus it needs some work to route the reader, validator and the document. `SchemaValidatingReader` is a helper class that doing such work. @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -## SAX parsing +## SAX parsing {#SaxParsing} For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -## Serialization +## Serialization {#Serialization} It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema. @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { Of course, if your application only needs SAX-style serialization, it can simply send SAX events to `SchemaValidator` instead of `Writer`. -# Remote Schema +# Remote Schema {#RemoteSchema} JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](doc/pointer.md) referencing to a local or remote schema. Local pointer is prefixed with `#`, while remote pointer is an relative or absolute URI. For example: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -# Conformance +# Conformance {#Conformance} RapidJSON passed 262 out of 263 tests in [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4). @@ -176,7 +176,7 @@ The failed test is "changed scope ref invalid" of "change resolution scope" in ` Besides, the `format` schema keyword for string values is ignored, since it is not required by the specification. -## Regular Expression +## Regular Expression {#RegEx} The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern. @@ -211,7 +211,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d For C++11 compiler, it is also possible to use the `std::regex` by defining `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. If your schemas do not need `pattern` and `patternProperties`, you can set both macros to zero to disable this feature, which will reduce some code size. -# Performance +# Performance {#Performance} Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. diff --git a/doc/schema.zh-cn.md b/doc/schema.zh-cn.md index 1dd7e79..c85177f 100644 --- a/doc/schema.zh-cn.md +++ b/doc/schema.zh-cn.md @@ -8,7 +8,7 @@ RapidJSON 实现了一个 [JSON Schema Draft v4](http://json-schema.org/document [TOC] -# 基本用法 +# 基本用法 {#BasicUsage} 首先,你要把 JSON Schema 解析成 `Document`,再把它编译成一个 `SchemaDocument`。 @@ -52,11 +52,11 @@ if (!d.Accept(validator)) { * 一个 `SchemaDocment` 能被多个 `SchemaValidator` 引用。它不会被 `SchemaValidator` 修改。 * 可以重复使用一个 `SchemaValidator` 来校验多个文件。在校验其他文件前,须先调用 `validator.Reset()`。 -# 在解析/生成时进行校验 +# 在解析/生成时进行校验 {#ParsingSerialization} 与大部分 JSON Schema 校验器有所不同,RapidJSON 提供了一个基于 SAX 的 schema 校验器实现。因此,你可以在输入流解析 JSON 的同时进行校验。若校验器遇到一个与 schema 不符的值,就会立即终止解析。这设计对于解析大型 JSON 文件时特别有用。 -## DOM 解析 +## DOM 解析 {#DomParsing} 在使用 DOM 进行解析时,`Document` 除了接收 SAX 事件外,还需做一些准备及结束工作,因此,为了连接 `Reader`、`SchemaValidator` 和 `Document` 要做多一点事情。`SchemaValidatingReader` 是一个辅助类去做那些工作。 @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -## SAX 解析 +## SAX 解析 {#SaxParsing} 使用 SAX 解析时,情况就简单得多。若只需要校验 JSON 而无需进一步处理,那么仅需要: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -## 生成 +## 生成 {#Serialization} 我们也可以在生成(serialization)的时候进行校验。这能确保输出的 JSON 符合一个 JSON Schema。 @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { 当然,如果你的应用仅需要 SAX 风格的生成,那么只需要把 SAX 事件由原来发送到 `Writer`,改为发送到 `SchemaValidator`。 -# 远程 Schema +# 远程 Schema {#RemoteSchema} JSON Schema 支持 [`$ref` 关键字](http://spacetelescope.github.io/understanding-json-schema/structuring.html),它是一个 [JSON pointer](doc/pointer.zh-cn.md) 引用至一个本地(local)或远程(remote) schema。本地指针的首字符是 `#`,而远程指针是一个相对或绝对 URI。例如: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -# 标准的符合程度 +# 标准的符合程度 {#Conformance} RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4) 中 263 个测试的 262 个。 @@ -176,7 +176,7 @@ RapidJSON 通过了 [JSON Schema Test Suite](https://github.com/json-schema/JSON 除此以外,关于字符串类型的 `format` schema 关键字也会被忽略,因为标准中并没需求必须实现。 -## 正则表达式 +## 正则表达式 {#RegEx} `pattern` 及 `patternProperties` 这两个 schema 关键字使用了正则表达式去匹配所需的模式。 @@ -211,7 +211,7 @@ RapidJSON 实现了一个简单的 NFA 正则表达式引擎,并预设使用 对于使用 C++11 编译器的使用者,也可使用 `std::regex`,只需定义 `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` 及 `RAPIDJSON_SCHEMA_USE_STDREGEX=1`。若你的 schema 无需使用 `pattern` 或 `patternProperties`,可以把两个宏都设为零,以禁用此功能,这样做可节省一些代码体积。 -# 性能 +# 性能 {#Performance} 大部分 C++ JSON 库都未支持 JSON Schema。因此我们尝试按照 [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark) 去评估 RapidJSON 的 JSON Schema 校验器。该评测测试了 11 个运行在 node.js 上的 JavaScript 库。 From f4b1f761f31352348bf142095643d61e84795dc8 Mon Sep 17 00:00:00 2001 From: "M.Tayel" <32839716+m-tayel@users.noreply.github.com> Date: Tue, 24 Oct 2017 12:25:47 +0200 Subject: [PATCH 082/128] Fixed typo in CMake file --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 950d115..8d69855 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ if(CCACHE_FOUND) endif(CCACHE_FOUND) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - if(${RAPIDJSON_DISABLE_INSTRUMENTATION_OPT}) + if(${RAPIDJSON_ENABLE_INSTRUMENTATION_OPT}) if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") else() From 1be14d04a05fc8bcb7ad2fdb72fb7f71f50a337f Mon Sep 17 00:00:00 2001 From: clach04 Date: Thu, 26 Oct 2017 21:19:54 -0700 Subject: [PATCH 083/128] Fix issue #1104 Solaris compilation errors fread()/fwrite() Explicit std name space for fread() and fwrite(). --- include/rapidjson/filereadstream.h | 2 +- include/rapidjson/filewritestream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index b56ea13..f1bfb7d 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -68,7 +68,7 @@ private: ++current_; else if (!eof_) { count_ += readCount_; - readCount_ = fread(buffer_, 1, bufferSize_, fp_); + readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h index 6378dd6..3811f8b 100644 --- a/include/rapidjson/filewritestream.h +++ b/include/rapidjson/filewritestream.h @@ -62,7 +62,7 @@ public: void Flush() { if (current_ != buffer_) { - size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); if (result < static_cast(current_ - buffer_)) { // failure deliberately ignored at this time // added to avoid warn_unused_result build errors From 8684c9960de4e2b028ea0f51a0d5dd8e68ff4345 Mon Sep 17 00:00:00 2001 From: Martin Lindhe Date: Sat, 4 Nov 2017 10:32:02 +0100 Subject: [PATCH 084/128] fix some typos --- CHANGELOG.md | 2 +- doc/dom.md | 2 +- doc/encoding.md | 2 +- doc/faq.md | 16 ++++++++-------- doc/performance.md | 2 +- doc/pointer.md | 2 +- doc/sax.md | 2 +- doc/schema.md | 2 +- doc/tutorial.md | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9d603c..1c580bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -140,7 +140,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). * Redo all documentation (English, Simplified Chinese) ### Changed -* Copyright ownership transfered to THL A29 Limited (a Tencent company). +* Copyright ownership transferred to THL A29 Limited (a Tencent company). * Migrating from Premake to CMAKE (#192) * Resolve all warning reports diff --git a/doc/dom.md b/doc/dom.md index 6c541fe..25ffbd2 100644 --- a/doc/dom.md +++ b/doc/dom.md @@ -241,7 +241,7 @@ Some techniques about using DOM API is discussed here. ## DOM as SAX Event Publisher -In RapidJSON, stringifying a DOM with `Writer` may be look a little bit weired. +In RapidJSON, stringifying a DOM with `Writer` may be look a little bit weird. ~~~~~~~~~~cpp // ... diff --git a/doc/encoding.md b/doc/encoding.md index 8f8ff7f..e663aea 100644 --- a/doc/encoding.md +++ b/doc/encoding.md @@ -10,7 +10,7 @@ The earlier [RFC4627](http://www.ietf.org/rfc/rfc4627.txt) stated that, > (in §6) JSON may be represented using UTF-8, UTF-16, or UTF-32. When JSON is written in UTF-8, JSON is 8bit compatible. When JSON is written in UTF-16 or UTF-32, the binary content-transfer-encoding must be used. -RapidJSON supports various encodings. It can also validate the encodings of JSON, and transconding JSON among encodings. All these features are implemented internally, without the need for external libraries (e.g. [ICU](http://site.icu-project.org/)). +RapidJSON supports various encodings. It can also validate the encodings of JSON, and transcoding JSON among encodings. All these features are implemented internally, without the need for external libraries (e.g. [ICU](http://site.icu-project.org/)). [TOC] diff --git a/doc/faq.md b/doc/faq.md index 74d770d..d5697ff 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -116,7 +116,7 @@ ~~~~~~~~~~cpp Value(kObjectType).Swap(d); ~~~~~~~~~~ - or equivalent, but sightly longer to type: + or equivalent, but slightly longer to type: ~~~~~~~~~~cpp d.Swap(Value(kObjectType).Move()); ~~~~~~~~~~ @@ -140,11 +140,11 @@ } ~~~~~~~~~~ - The most important requirement to take care of document and value life-cycle as well as consistent memory managent using the right allocator during the value transfer. + The most important requirement to take care of document and value life-cycle as well as consistent memory management using the right allocator during the value transfer. Simple yet most efficient way to achieve that is to modify the `address` definition above to initialize it with allocator of the `person` document, then we just add the root member of the value: ~~~~~~~~~~cpp - Documnet address(person.GetAllocator()); + Document address(person.GetAllocator()); ... person["person"].AddMember("address", address["address"], person.GetAllocator()); ~~~~~~~~~~ @@ -174,7 +174,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres 3. Why do I need to provide the length of string? - Since C string is null-terminated, the length of string needs to be computed via `strlen()`, with linear runtime complexity. This incurs an unncessary overhead of many operations, if the user already knows the length of string. + Since C string is null-terminated, the length of string needs to be computed via `strlen()`, with linear runtime complexity. This incurs an unnecessary overhead of many operations, if the user already knows the length of string. Also, RapidJSON can handle `\u0000` (null character) within a string. If a string contains null characters, `strlen()` cannot return the true length of it. In such case user must provide the length of string explicitly. @@ -204,7 +204,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres 2. Can it validate the encoding? - Yes, just pass `kParseValidateEncodingFlag` to `Parse()`. If there is invalid encoding in the stream, it wil generate `kParseErrorStringInvalidEncoding` error. + Yes, just pass `kParseValidateEncodingFlag` to `Parse()`. If there is invalid encoding in the stream, it will generate `kParseErrorStringInvalidEncoding` error. 3. What is surrogate pair? Does RapidJSON support it? @@ -248,7 +248,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres 1. Is RapidJSON really fast? - Yes. It may be the fastest open source JSON library. There is a [benchmark](https://github.com/miloyip/nativejson-benchmark) for evaluating performance of C/C++ JSON libaries. + Yes. It may be the fastest open source JSON library. There is a [benchmark](https://github.com/miloyip/nativejson-benchmark) for evaluating performance of C/C++ JSON libraries. 2. Why is it fast? @@ -262,13 +262,13 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres The design of RapidJSON aims at reducing memory footprint. - In the SAX API, `Reader` consumes memory portional to maximum depth of JSON tree, plus maximum length of JSON string. + In the SAX API, `Reader` consumes memory proportional to maximum depth of JSON tree, plus maximum length of JSON string. In the DOM API, each `Value` consumes exactly 16/24 bytes for 32/64-bit architecture respectively. RapidJSON also uses a special memory allocator to minimize overhead of allocations. 5. What is the purpose of being high performance? - Some applications need to process very large JSON files. Some server-side applications need to process huge amount of JSONs. Being high performance can improve both latency and throuput. In a broad sense, it will also save energy. + Some applications need to process very large JSON files. Some server-side applications need to process huge amount of JSONs. Being high performance can improve both latency and throughput. In a broad sense, it will also save energy. ## Gossip diff --git a/doc/performance.md b/doc/performance.md index 7b18730..6f9e1bf 100644 --- a/doc/performance.md +++ b/doc/performance.md @@ -1,6 +1,6 @@ # Performance -There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 37 JSON libaries. +There is a [native JSON benchmark collection] [1] which evaluates speed, memory usage and code size of various operations among 37 JSON libraries. [1]: https://github.com/miloyip/nativejson-benchmark diff --git a/doc/pointer.md b/doc/pointer.md index b343d78..9a0e5ca 100644 --- a/doc/pointer.md +++ b/doc/pointer.md @@ -211,7 +211,7 @@ p.Stringify(sb); std::cout << sb.GetString() << std::endl; ~~~ -It can also stringify to URI fragment reprsentation by `StringifyUriFragment()`. +It can also stringify to URI fragment representation by `StringifyUriFragment()`. # User-Supplied Tokens {#UserSuppliedTokens} diff --git a/doc/sax.md b/doc/sax.md index 4867880..874361f 100644 --- a/doc/sax.md +++ b/doc/sax.md @@ -126,7 +126,7 @@ When the `Reader` encounters a JSON number, it chooses a suitable C++ type mappi When the `Reader` encounters the beginning of an object, it calls `StartObject()`. An object in JSON is a set of name-value pairs. If the object contains members it first calls `Key()` for the name of member, and then calls functions depending on the type of the value. These calls of name-value pairs repeat until calling `EndObject(SizeType memberCount)`. Note that the `memberCount` parameter is just an aid for the handler; users who do not need this parameter may ignore it. -Arrays are similar to objects, but simpler. At the beginning of an array, the `Reader` calls `BeginArary()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler. +Arrays are similar to objects, but simpler. At the beginning of an array, the `Reader` calls `BeginArray()`. If there is elements, it calls functions according to the types of element. Similarly, in the last call `EndArray(SizeType elementCount)`, the parameter `elementCount` is just an aid for the handler. Every handler function returns a `bool`. Normally it should return `true`. If the handler encounters an error, it can return `false` to notify the event publisher to stop further processing. diff --git a/doc/schema.md b/doc/schema.md index 5e396ce..b454225 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -49,7 +49,7 @@ if (!d.Accept(validator)) { Some notes: -* One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. +* One `SchemaDocument` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. * A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first. # Validation during parsing/serialization {#ParsingSerialization} diff --git a/doc/tutorial.md b/doc/tutorial.md index 167b81d..3fa63c9 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -68,7 +68,7 @@ printf("t = %s\n", document["t"].GetBool() ? "true" : "false"); t = true ~~~~~~~~~~ -JSON null can be queryed with `IsNull()`. +JSON null can be queried with `IsNull()`. ~~~~~~~~~~cpp printf("n = %s\n", document["n"].IsNull() ? "null" : "?"); ~~~~~~~~~~ From 86e280f636b3578ea44171dc144dea7f234644f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Dupuis?= Date: Thu, 23 Nov 2017 09:16:20 +0100 Subject: [PATCH 085/128] Solves #1108. The default copy constructor of GenericPointer will use the allocator of the copied object. The extra copy constructor that takes an allocator as a parameter is distinct if someone really wants to create a copy with a null allocator. --- include/rapidjson/pointer.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h index 0f377ef..217e71c 100644 --- a/include/rapidjson/pointer.h +++ b/include/rapidjson/pointer.h @@ -165,7 +165,12 @@ public: GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Copy constructor. - GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + *this = rhs; + } + + //! Copy constructor. + GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { *this = rhs; } From 4e1c7363cc958ece4fd72dd4a23cad108f72d141 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 24 Nov 2017 15:46:44 +0100 Subject: [PATCH 086/128] CMake: avoid neeless variable expansion CMake will automatically expand strings that are variable names in if(). --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d69855..a0f9bdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,9 +51,9 @@ if(CCACHE_FOUND) endif() endif(CCACHE_FOUND) -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - if(${RAPIDJSON_ENABLE_INSTRUMENTATION_OPT}) - if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") else() #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. @@ -84,7 +84,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") endif() endif() elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "powerpc" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64" OR "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "ppc64le") + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") else() #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. @@ -105,7 +105,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") endif() endif() -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") add_definitions(-D_CRT_SECURE_NO_WARNINGS=1) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") elseif (CMAKE_CXX_COMPILER_ID MATCHES "XL") From 4c9a28a28e078ef7e1eb7e98cdb2dfabd4b378ca Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 24 Nov 2017 15:48:43 +0100 Subject: [PATCH 087/128] CMake: do not pass -march=native or -mcpu=native when crosscompiling --- CMakeLists.txt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0f9bdc..cc3a41b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ if(CCACHE_FOUND) endif(CCACHE_FOUND) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT) + if(RAPIDJSON_ENABLE_INSTRUMENTATION_OPT AND NOT CMAKE_CROSSCOMPILING) if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") else() @@ -84,11 +84,13 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() endif() elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") - else() - #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") + if(NOT CMAKE_CROSSCOMPILING) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "powerpc" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "ppc64le") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=native") + else() + #FIXME: x86 is -march=native, but doesn't mean every arch is this option. To keep original project's compatibility, I leave this except POWER. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") + endif() endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -Wno-missing-field-initializers") set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough) From ff59b6179dc70903fc04ad891d1295c84090f9b5 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Fri, 24 Nov 2017 17:00:53 +0100 Subject: [PATCH 088/128] CMake: automatically handle C++11 settings if possible --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc3a41b..c825beb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,10 @@ option(RAPIDJSON_BUILD_THIRDPARTY_GTEST "Use gtest installation in `thirdparty/gtest` by default if available" OFF) option(RAPIDJSON_BUILD_CXX11 "Build rapidjson with C++11 (gcc/clang)" ON) +if(RAPIDJSON_BUILD_CXX11) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED TRUE) +endif() option(RAPIDJSON_BUILD_ASAN "Build rapidjson with address sanitizer (gcc/clang)" OFF) option(RAPIDJSON_BUILD_UBSAN "Build rapidjson with undefined behavior sanitizer (gcc/clang)" OFF) @@ -62,7 +66,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror") set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wsign-conversion) - if (RAPIDJSON_BUILD_CXX11) + if (RAPIDJSON_BUILD_CXX11 AND CMAKE_VERSION VERSION_LESS 3.1) if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7.0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") else() @@ -94,7 +98,7 @@ elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror -Wno-missing-field-initializers") set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough) - if (RAPIDJSON_BUILD_CXX11) + if (RAPIDJSON_BUILD_CXX11 AND CMAKE_VERSION VERSION_LESS 3.1) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() if (RAPIDJSON_BUILD_ASAN) From 44f2f9aa536d8cced21f4e9c58f7d9d98bd88a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Dupuis?= Date: Mon, 27 Nov 2017 10:38:01 +0100 Subject: [PATCH 089/128] Added relevant unit tests for issue #1108 suggested improvement. --- test/unittest/pointertest.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp index d5a688d..855d822 100644 --- a/test/unittest/pointertest.cpp +++ b/test/unittest/pointertest.cpp @@ -462,7 +462,8 @@ TEST(Pointer, ConstructorWithToken) { TEST(Pointer, CopyConstructor) { { - Pointer p("/foo/0"); + CrtAllocator allocator; + Pointer p("/foo/0", &allocator); Pointer q(p); EXPECT_TRUE(q.IsValid()); EXPECT_EQ(2u, q.GetTokenCount()); @@ -471,6 +472,7 @@ TEST(Pointer, CopyConstructor) { EXPECT_EQ(1u, q.GetTokens()[1].length); EXPECT_STREQ("0", q.GetTokens()[1].name); EXPECT_EQ(0u, q.GetTokens()[1].index); + EXPECT_EQ(&p.GetAllocator(), &q.GetAllocator()); } // Static tokens @@ -489,7 +491,8 @@ TEST(Pointer, CopyConstructor) { TEST(Pointer, Assignment) { { - Pointer p("/foo/0"); + CrtAllocator allocator; + Pointer p("/foo/0", &allocator); Pointer q; q = p; EXPECT_TRUE(q.IsValid()); @@ -499,6 +502,7 @@ TEST(Pointer, Assignment) { EXPECT_EQ(1u, q.GetTokens()[1].length); EXPECT_STREQ("0", q.GetTokens()[1].name); EXPECT_EQ(0u, q.GetTokens()[1].index); + EXPECT_NE(&p.GetAllocator(), &q.GetAllocator()); q = q; EXPECT_TRUE(q.IsValid()); EXPECT_EQ(2u, q.GetTokenCount()); @@ -507,6 +511,7 @@ TEST(Pointer, Assignment) { EXPECT_EQ(1u, q.GetTokens()[1].length); EXPECT_STREQ("0", q.GetTokens()[1].name); EXPECT_EQ(0u, q.GetTokens()[1].index); + EXPECT_NE(&p.GetAllocator(), &q.GetAllocator()); } // Static tokens From 25c1b78f3c905284d7194430f083b0381d7aff83 Mon Sep 17 00:00:00 2001 From: Matthis Thorade Date: Mon, 4 Dec 2017 13:15:01 +0100 Subject: [PATCH 090/128] ignore DS_Store files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index e7e8fba..1d3073f 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ Doxyfile Doxyfile.zh-cn DartConfiguration.tcl *.nupkg + +# Files created by OS +*.DS_Store From 195dc90d27bf6552cab4503cc842b2d3bd3b3828 Mon Sep 17 00:00:00 2001 From: Matthis Thorade Date: Mon, 4 Dec 2017 13:18:51 +0100 Subject: [PATCH 091/128] Delete .DS_Store --- bin/jsonschema/remotes/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bin/jsonschema/remotes/.DS_Store diff --git a/bin/jsonschema/remotes/.DS_Store b/bin/jsonschema/remotes/.DS_Store deleted file mode 100644 index 1d098a4103d67f2b3b336934f3d7f42b462861a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOHRWu5S@X7Ds|H(?0kjZAgaO%dI3btXOYNNp?e>&D;7NuZ$2PWB6c8zW+eOB z^Ks%A#p59&UhngYXh}qKG(ncZgot|5bmq<%K-M+xX_ue7{;rgMVxhmNl6SwP2P)K4 zrjz#{8T!Z7rYpnNcX53hIFz={`93>*C>7{`CI$;>GS&XK|+FoU?3O>27-Z~ zU;sH=WWF$rJ{SlFf`JbPv%iZPLM Date: Mon, 4 Dec 2017 13:19:05 +0100 Subject: [PATCH 092/128] Delete .DS_Store --- bin/jsonschema/tests/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bin/jsonschema/tests/.DS_Store diff --git a/bin/jsonschema/tests/.DS_Store b/bin/jsonschema/tests/.DS_Store deleted file mode 100644 index dae9b18efac169b4f44a57c7926495a005607a85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKJ8r`;3?&nz2$02NM_r*n4j=^133`F1H98qEkT$!goU2Fc<7bHBbW4X8j{x-~ zicf;xV45PL`*Z&!(u&9iZYUQUmS+3r3tMGGfpDDhDZBpTZFn8WVUc}1VB81kpAHP(0stF?-7xoF z0$3~ntcg<~A}|dqFsPa>h6Ww+l6f_83JkhvHXoWdYj!B=x8wZc>7q4|BNdLa}rlnfC~I81+?j&yFH$iwRQ10tF;CG0=JwmxEbb7!QkZ>=;as-E60zX b6nVww*sqCGpwkg|I*>mDrVEV<{I&w$e{~fm From 79d5e236739c72851d66b3d5cb671caaa6585ea1 Mon Sep 17 00:00:00 2001 From: Matthis Thorade Date: Mon, 4 Dec 2017 13:19:14 +0100 Subject: [PATCH 093/128] Delete .DS_Store --- bin/jsonschema/tests/draft4/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bin/jsonschema/tests/draft4/.DS_Store diff --git a/bin/jsonschema/tests/draft4/.DS_Store b/bin/jsonschema/tests/draft4/.DS_Store deleted file mode 100644 index ef142295ea00d1d19fc3d30cc4e82dd207530825..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T^D5T4N$3SRc8x4go>L0IYo$i9Huf(orExO?vd?#YAC<2OGpmKHn+A~FM+ zFPY3tnh%;}h={j`c0;r#q6$rrrL!PnUYt5}=L;ZfjzTYVPhI=kbPI|8qDj8JqCx}h z=^1$X{)bX@53|YcakFbmKiF=rZcj9aqIv5BBrVO0ha4q-$4St!$ zB7YhZqhKHy_-738s@~OGY|8J}+4khFO=x#$BH}kn2ZH|O5rBc5BUd_U^GW*f%Z{U= TWD&cD1LGl}goFwPeu04xBO^7X From d75bb90a5dd8c5946ce7496748d1cea842aabc0f Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Tue, 12 Dec 2017 21:16:07 +0100 Subject: [PATCH 094/128] Avoid inheritance from std::iterator Instead of inheriting from the deprecated std::iterator template, define the member typedefs needed for std::iterator_traits directly. Closes #1131. --- include/rapidjson/document.h | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 094a07e..eb6d7dc 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -45,7 +45,7 @@ RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_N #endif // __GNUC__ #ifndef RAPIDJSON_NOMEMBERITERATORCLASS -#include // std::iterator, std::random_access_iterator_tag +#include // std::random_access_iterator_tag #endif #if RAPIDJSON_HAS_CXX11_RVALUE_REFS @@ -98,16 +98,13 @@ struct GenericMember { \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator */ template -class GenericMemberIterator - : public std::iterator >::Type> { +class GenericMemberIterator { friend class GenericValue; template friend class GenericMemberIterator; typedef GenericMember PlainType; typedef typename internal::MaybeAddConst::Type ValueType; - typedef std::iterator BaseType; public: //! Iterator type itself @@ -117,12 +114,21 @@ public: //! Non-constant iterator type typedef GenericMemberIterator NonConstIterator; + /** \name std::iterator_traits support */ + //@{ + typedef ValueType value_type; + typedef ValueType * pointer; + typedef ValueType & reference; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + //@} + //! Pointer to (const) GenericMember - typedef typename BaseType::pointer Pointer; + typedef pointer Pointer; //! Reference to (const) GenericMember - typedef typename BaseType::reference Reference; + typedef reference Reference; //! Signed integer type (e.g. \c ptrdiff_t) - typedef typename BaseType::difference_type DifferenceType; + typedef difference_type DifferenceType; //! Default constructor (singular value) /*! Creates an iterator pointing to no element. From f2a28ee4720f34efae516c04eccb97e6820644b2 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Wed, 13 Dec 2017 21:53:18 +0800 Subject: [PATCH 095/128] Add archiver example A simple (de)serialization framework using DOM and SAX API --- example/CMakeLists.txt | 2 + example/archiver/archiver.cpp | 292 ++++++++++++++++++++++++++++++ example/archiver/archiver.h | 139 ++++++++++++++ example/archiver/archivertest.cpp | 281 ++++++++++++++++++++++++++++ 4 files changed, 714 insertions(+) create mode 100644 example/archiver/archiver.cpp create mode 100644 example/archiver/archiver.h create mode 100644 example/archiver/archivertest.cpp diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index e00f77a..ff54199 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -32,6 +32,8 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") endif() +add_executable(archivertest archiver/archiver.cpp archiver/archivertest.cpp) + foreach (example ${EXAMPLES}) add_executable(${example} ${example}/${example}.cpp) endforeach() diff --git a/example/archiver/archiver.cpp b/example/archiver/archiver.cpp new file mode 100644 index 0000000..59ae4c4 --- /dev/null +++ b/example/archiver/archiver.cpp @@ -0,0 +1,292 @@ +#include "archiver.h" +#include +#include +#include "rapidjson/document.h" +#include "rapidjson/prettywriter.h" +#include "rapidjson/stringbuffer.h" + +using namespace rapidjson; + +struct JsonReaderStackItem { + enum State { + BeforeStart, //!< An object/array is in the stack but it is not yet called by StartObject()/StartArray(). + Started, //!< An object/array is called by StartObject()/StartArray(). + Closed //!< An array is closed after read all element, but before EndArray(). + }; + + JsonReaderStackItem(const Value* value, State state) : value(value), state(state), index() {} + + const Value* value; + State state; + SizeType index; // For array iteration +}; + +typedef std::stack JsonReaderStack; + +#define DOCUMENT reinterpret_cast(mDocument) +#define STACK (reinterpret_cast(mStack)) +#define TOP (STACK->top()) +#define CURRENT (*TOP.value) + +JsonReader::JsonReader(const char* json) : mDocument(), mStack(), mError(false) { + mDocument = new Document; + DOCUMENT->Parse(json); + if (DOCUMENT->HasParseError()) + mError = true; + else { + mStack = new JsonReaderStack; + STACK->push(JsonReaderStackItem(DOCUMENT, JsonReaderStackItem::BeforeStart)); + } +} + +JsonReader::~JsonReader() { + delete DOCUMENT; + delete STACK; +} + +// Archive concept +JsonReader& JsonReader::StartObject() { + if (!mError) { + if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::BeforeStart) + TOP.state = JsonReaderStackItem::Started; + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::EndObject() { + if (!mError) { + if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started) + Next(); + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::Member(const char* name) { + if (!mError) { + if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started) { + Value::ConstMemberIterator memberItr = CURRENT.FindMember(name); + if (memberItr != CURRENT.MemberEnd()) + STACK->push(JsonReaderStackItem(&memberItr->value, JsonReaderStackItem::BeforeStart)); + else + mError = true; + } + else + mError = true; + } + return *this; +} + +bool JsonReader::HasMember(const char* name) const { + if (!mError && CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started) + return CURRENT.HasMember(name); + return false; +} + +JsonReader& JsonReader::StartArray(size_t* size) { + if (!mError) { + if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::BeforeStart) { + TOP.state = JsonReaderStackItem::Started; + if (size) + *size = CURRENT.Size(); + + if (!CURRENT.Empty()) { + const Value* value = &CURRENT[TOP.index]; + STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart)); + } + else + TOP.state = JsonReaderStackItem::Closed; + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::EndArray() { + if (!mError) { + if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::Closed) + Next(); + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(bool& b) { + if (!mError) { + if (CURRENT.IsBool()) { + b = CURRENT.GetBool(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(unsigned& u) { + if (!mError) { + if (CURRENT.IsUint()) { + u = CURRENT.GetUint(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(int& i) { + if (!mError) { + if (CURRENT.IsInt()) { + i = CURRENT.GetInt(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(double& d) { + if (!mError) { + if (CURRENT.IsNumber()) { + d = CURRENT.GetDouble(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::operator&(std::string& s) { + if (!mError) { + if (CURRENT.IsString()) { + s = CURRENT.GetString(); + Next(); + } + else + mError = true; + } + return *this; +} + +JsonReader& JsonReader::SetNull() { + // This function is for JsonWriter only. + mError = true; + return *this; +} + +void JsonReader::Next() { + if (!mError) { + assert(!STACK->empty()); + STACK->pop(); + + if (!STACK->empty() && CURRENT.IsArray()) { + if (TOP.state == JsonReaderStackItem::Started) { // Otherwise means reading array item pass end + if (TOP.index < CURRENT.Size() - 1) { + const Value* value = &CURRENT[++TOP.index]; + STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart)); + } + else + TOP.state = JsonReaderStackItem::Closed; + } + else + mError = true; + } + } +} + +#undef DOCUMENT +#undef STACK +#undef TOP +#undef CURRENT + +//////////////////////////////////////////////////////////////////////////////// +// JsonWriter + +#define WRITER reinterpret_cast*>(mWriter) +#define STREAM reinterpret_cast(mStream) + +JsonWriter::JsonWriter() : mWriter(), mStream() { + mStream = new StringBuffer; + mWriter = new PrettyWriter(*STREAM); +} + +JsonWriter::~JsonWriter() { + delete WRITER; + delete STREAM; +} + +const char* JsonWriter::GetString() const { + return STREAM->GetString(); +} + +JsonWriter& JsonWriter::StartObject() { + WRITER->StartObject(); + return *this; +} + +JsonWriter& JsonWriter::EndObject() { + WRITER->EndObject(); + return *this; +} + +JsonWriter& JsonWriter::Member(const char* name) { + WRITER->String(name, static_cast(strlen(name))); + return *this; +} + +bool JsonWriter::HasMember(const char*) const { + // This function is for JsonReader only. + assert(false); + return false; +} + +JsonWriter& JsonWriter::StartArray(size_t*) { + WRITER->StartArray(); + return *this; +} + +JsonWriter& JsonWriter::EndArray() { + WRITER->EndArray(); + return *this; +} + +JsonWriter& JsonWriter::operator&(bool& b) { + WRITER->Bool(b); + return *this; +} + +JsonWriter& JsonWriter::operator&(unsigned& u) { + WRITER->Uint(u); + return *this; +} + +JsonWriter& JsonWriter::operator&(int& i) { + WRITER->Int(i); + return *this; +} + +JsonWriter& JsonWriter::operator&(double& d) { + WRITER->Double(d); + return *this; +} + +JsonWriter& JsonWriter::operator&(std::string& s) { + WRITER->String(s.c_str(), static_cast(s.size())); + return *this; +} + +JsonWriter& JsonWriter::SetNull() { + WRITER->Null(); + return *this; +} + +#undef STREAM +#undef WRITER diff --git a/example/archiver/archiver.h b/example/archiver/archiver.h new file mode 100644 index 0000000..c7e74f0 --- /dev/null +++ b/example/archiver/archiver.h @@ -0,0 +1,139 @@ +#ifndef ARCHIVER_H_ +#define ARCHIVER_H_ + +#include +#include + +/** +\class Archiver +\brief Archiver concept + +Archiver can be a reader or writer for serialization or deserialization respectively. + +class Archiver { +public: + /// \returns true if the archiver is in normal state. false if it has errors. + operator bool() const; + + /// Starts an object + Archiver& StartObject(); + + /// After calling StartObject(), assign a member with a name + Archiver& Member(const char* name); + + /// After calling StartObject(), check if a member presents + bool HasMember(const char* name) const; + + /// Ends an object + Archiver& EndObject(); + + /// Starts an array + /// \param size If Archiver::IsReader is true, the size of array is written. + Archiver& StartArray(size_t* size = 0); + + /// Ends an array + Archiver& EndArray(); + + /// Read/Write primitive types. + Archiver& operator&(bool& b); + Archiver& operator&(unsigned& u); + Archiver& operator&(int& i); + Archiver& operator&(double& d); + Archiver& operator&(std::string& s); + + /// Write primitive types. + Archiver& SetNull(); + + //! Whether it is a reader. + static const bool IsReader; + + //! Whether it is a writer. + static const bool IsWriter; +}; +*/ + +/// Represents a JSON reader which implements Archiver concept. +class JsonReader { +public: + /// Constructor. + /** + \param json A non-const source json string for in-situ parsing. + \note in-situ means the source JSON string will be modified after parsing. + */ + JsonReader(const char* json); + + /// Destructor. + ~JsonReader(); + + // Archive concept + + operator bool() const { return !mError; } + + JsonReader& StartObject(); + JsonReader& Member(const char* name); + bool HasMember(const char* name) const; + JsonReader& EndObject(); + + JsonReader& StartArray(size_t* size = nullptr); + JsonReader& EndArray(); + + JsonReader& operator&(bool& b); + JsonReader& operator&(unsigned& u); + JsonReader& operator&(int& i); + JsonReader& operator&(double& d); + JsonReader& operator&(std::string& s); + + JsonReader& SetNull(); + + static const bool IsReader = true; + static const bool IsWriter = !IsReader; + +private: + void Next(); + + // PIMPL + void* mDocument; ///< DOM result of parsing. + void* mStack; ///< Stack for iterating the DOM + bool mError; ///< Whether an error is occured. +}; + +class JsonWriter { +public: + /// Constructor. + JsonWriter(); + + /// Destructor. + ~JsonWriter(); + + /// Obtains the serialized JSON string. + const char* GetString() const; + + // Archive concept + + operator bool() const { return true; } + + JsonWriter& StartObject(); + JsonWriter& Member(const char* name); + bool HasMember(const char* name) const; + JsonWriter& EndObject(); + + JsonWriter& StartArray(size_t* size = 0); + JsonWriter& EndArray(); + + JsonWriter& operator&(bool& b); + JsonWriter& operator&(unsigned& u); + JsonWriter& operator&(int& i); + JsonWriter& operator&(double& d); + JsonWriter& operator&(std::string& s); + JsonWriter& SetNull(); + + static const bool IsReader = false; + static const bool IsWriter = !IsReader; + +private: + // PIMPL idiom + void* mWriter; ///< JSON writer. + void* mStream; ///< Stream buffer. +}; + +#endif // ARCHIVER_H__ diff --git a/example/archiver/archivertest.cpp b/example/archiver/archivertest.cpp new file mode 100644 index 0000000..788db36 --- /dev/null +++ b/example/archiver/archivertest.cpp @@ -0,0 +1,281 @@ +#include "archiver.h" +#include +#include + +////////////////////////////////////////////////////////////////////////////// +// Test1: simple object + +struct Student { + std::string name; + unsigned age; + double height; + bool canSwim; +}; + +template +Archiver& operator&(Archiver& ar, Student& s) { + ar.StartObject(); + ar.Member("name") & s.name; + ar.Member("age") & s.age; + ar.Member("height") & s.height; + ar.Member("canSwim") & s.canSwim; + return ar.EndObject(); +} + +std::ostream& operator<<(std::ostream& os, const Student& s) { + return os << s.name << " " << s.age << " " << s.height << " " << s.canSwim; +} + +void test1() { + std::string json; + + // Serialize + { + Student s = { "Lua", 9, 150.5, true }; + + JsonWriter writer; + writer & s; + json = writer.GetString(); + std::cout << json << std::endl; + } + + // Deserialize + { + Student s; + JsonReader reader(json.c_str()); + reader & s; + std::cout << s << std::endl; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Test2: std::vector <=> JSON array +// +// You can map a JSON array to other data structures as well + +struct Group { + std::string groupName; + std::vector students; +}; + +template +Archiver& operator&(Archiver& ar, Group& g) { + ar.StartObject(); + + ar.Member("groupName"); + ar & g.groupName; + + ar.Member("students"); + size_t studentCount = g.students.size(); + ar.StartArray(&studentCount); + if (ar.IsReader) + g.students.resize(studentCount); + for (size_t i = 0; i < studentCount; i++) + ar & g.students[i]; + ar.EndArray(); + + return ar.EndObject(); +} + +std::ostream& operator<<(std::ostream& os, const Group& g) { + os << g.groupName << std::endl; + for (std::vector::const_iterator itr = g.students.begin(); itr != g.students.end(); ++itr) + os << *itr << std::endl; + return os; +} + +void test2() { + std::string json; + + // Serialize + { + Group g; + g.groupName = "Rainbow"; + + Student s1 = { "Lua", 9, 150.5, true }; + Student s2 = { "Mio", 7, 120.0, false }; + g.students.push_back(s1); + g.students.push_back(s2); + + JsonWriter writer; + writer & g; + json = writer.GetString(); + std::cout << json << std::endl; + } + + // Deserialize + { + Group g; + JsonReader reader(json.c_str()); + reader & g; + std::cout << g << std::endl; + } +} + +////////////////////////////////////////////////////////////////////////////// +// Test3: polymorphism & friend +// +// Note that friendship is not necessary but make things simpler. + +class Shape { +public: + virtual ~Shape() {} + virtual const char* GetType() const = 0; + virtual void Print(std::ostream& os) const = 0; + +protected: + Shape() {} + Shape(double x, double y) : x_(x), y_(y) {} + + template + friend Archiver& operator&(Archiver& ar, Shape& s); + + double x_, y_; +}; + +template +Archiver& operator&(Archiver& ar, Shape& s) { + ar.Member("x") & s.x_; + ar.Member("y") & s.y_; + return ar; +} + +class Circle : public Shape { +public: + Circle() {} + Circle(double x, double y, double radius) : Shape(x, y), radius_(radius) {} + ~Circle() {} + + const char* GetType() const { return "Circle"; } + + void Print(std::ostream& os) const { + os << "Circle (" << x_ << ", " << y_ << ")" << " radius = " << radius_; + } + +private: + template + friend Archiver& operator&(Archiver& ar, Circle& c); + + double radius_; +}; + +template +Archiver& operator&(Archiver& ar, Circle& c) { + ar & static_cast(c); + ar.Member("radius") & c.radius_; + return ar; +} + +class Box : public Shape { +public: + Box() {} + Box(double x, double y, double width, double height) : Shape(x, y), width_(width), height_(height) {} + ~Box() {} + + const char* GetType() const { return "Box"; } + + void Print(std::ostream& os) const { + os << "Box (" << x_ << ", " << y_ << ")" << " width = " << width_ << " height = " << height_; + } + +private: + template + friend Archiver& operator&(Archiver& ar, Box& b); + + double width_, height_; +}; + +template +Archiver& operator&(Archiver& ar, Box& b) { + ar & static_cast(b); + ar.Member("width") & b.width_; + ar.Member("height") & b.height_; + return ar; +} + +class Canvas { +public: + Canvas() {} + ~Canvas() { Clear(); } + + void Clear() { + for (std::vector::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr) + delete *itr; + } + + void AddShape(Shape* shape) { shapes_.push_back(shape); } + + void Print(std::ostream& os) { + for (std::vector::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr) { + (*itr)->Print(os); + std::cout << std::endl; + } + } + +private: + template + friend Archiver& operator&(Archiver& ar, Canvas& c); + + std::vector shapes_; +}; + +template +Archiver& operator&(Archiver& ar, Shape*& shape) { + std::string type = ar.IsReader ? "" : shape->GetType(); + ar.StartObject(); + ar.Member("type") & type; + if (type == "Circle") { + if (ar.IsReader) shape = new Circle; + ar & static_cast(*shape); + } + else if (type == "Box") { + if (ar.IsReader) shape = new Box; + ar & static_cast(*shape); + } + return ar.EndObject(); +} + +template +Archiver& operator&(Archiver& ar, Canvas& c) { + size_t shapeCount = c.shapes_.size(); + ar.StartArray(&shapeCount); + if (ar.IsReader) { + c.Clear(); + c.shapes_.resize(shapeCount); + } + for (size_t i = 0; i < shapeCount; i++) + ar & c.shapes_[i]; + return ar.EndArray(); +} + +void test3() { + std::string json; + + // Serialize + { + Canvas c; + c.AddShape(new Circle(1.0, 2.0, 3.0)); + c.AddShape(new Box(4.0, 5.0, 6.0, 7.0)); + + JsonWriter writer; + writer & c; + json = writer.GetString(); + std::cout << json << std::endl; + } + + // Deserialize + { + Canvas c; + JsonReader reader(json.c_str()); + reader & c; + c.Print(std::cout); + } +} + +////////////////////////////////////////////////////////////////////////////// + +int main() { + test1(); + test2(); + test3(); +} From 9bfa0bb567fd16f0fe7ea615e4b8139e8e64ce73 Mon Sep 17 00:00:00 2001 From: sjaques Date: Thu, 21 Dec 2017 13:40:28 +0100 Subject: [PATCH 096/128] Fix uninitilized member Reader::state_ --- include/rapidjson/reader.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 120c311..681dec2 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -544,7 +544,8 @@ public: /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ - GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : + stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. From 20d44d9c443290bc77e720bd65850a401fd7e9f4 Mon Sep 17 00:00:00 2001 From: Lele Gaifax Date: Fri, 22 Dec 2017 19:24:15 +0100 Subject: [PATCH 097/128] Fix FileWriteStream doc --- include/rapidjson/filewritestream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h index 3811f8b..8b48fee 100644 --- a/include/rapidjson/filewritestream.h +++ b/include/rapidjson/filewritestream.h @@ -25,7 +25,7 @@ RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_NAMESPACE_BEGIN -//! Wrapper of C file stream for input using fread(). +//! Wrapper of C file stream for output using fwrite(). /*! \note implements Stream concept */ From 53eadd218d705bd2dd5354eae46dd20e01dcd4e9 Mon Sep 17 00:00:00 2001 From: Haffon <31226194+Haffon@users.noreply.github.com> Date: Thu, 28 Dec 2017 16:31:26 +0800 Subject: [PATCH 098/128] GetParseOffset to GetErrorOffset --- doc/dom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dom.md b/doc/dom.md index 25ffbd2..0079b64 100644 --- a/doc/dom.md +++ b/doc/dom.md @@ -128,7 +128,7 @@ And the `InputStream` is type of input stream. ## Parse Error {#ParseError} -When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetParseOffset()`. +When the parse processing succeeded, the `Document` contains the parse results. When there is an error, the original DOM is *unchanged*. And the error state of parsing can be obtained by `bool HasParseError()`, `ParseErrorCode GetParseError()` and `size_t GetErrorOffset()`. Parse Error Code | Description --------------------------------------------|--------------------------------------------------- From 7dfeee862d3b47df7816a5b771a6523a61b62991 Mon Sep 17 00:00:00 2001 From: Haffon <31226194+Haffon@users.noreply.github.com> Date: Thu, 28 Dec 2017 16:32:26 +0800 Subject: [PATCH 099/128] GetParseOffset to GetErrorOffset --- doc/dom.zh-cn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dom.zh-cn.md b/doc/dom.zh-cn.md index b709485..9743b7a 100644 --- a/doc/dom.zh-cn.md +++ b/doc/dom.zh-cn.md @@ -128,7 +128,7 @@ GenericDocument& GenericDocument::Parse(const Ch* str); ## 解析错误 {#ParseError} -当解析过程顺利完成,`Document` 便会含有解析结果。当过程出现错误,原来的 DOM 会*维持不变*。可使用 `bool HasParseError()`、`ParseErrorCode GetParseError()` 及 `size_t GetParseOffset()` 获取解析的错误状态。 +当解析过程顺利完成,`Document` 便会含有解析结果。当过程出现错误,原来的 DOM 会*维持不变*。可使用 `bool HasParseError()`、`ParseErrorCode GetParseError()` 及 `size_t GetErrorOffset()` 获取解析的错误状态。 解析错误代号 | 描述 --------------------------------------------|--------------------------------------------------- From b8c12c9ccd3602eb50696a4e0ac2249f98937059 Mon Sep 17 00:00:00 2001 From: xiaoPierre Date: Thu, 11 Jan 2018 17:45:35 +0100 Subject: [PATCH 100/128] Bug when switching to std regex I could not switch to std regex after defining the two variables as in documents. Then I try to fix it in schema.h. --- include/rapidjson/schema.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 2713fb2..7493871 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -25,7 +25,7 @@ #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 #endif -#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) +#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) #define RAPIDJSON_SCHEMA_USE_STDREGEX 1 #else #define RAPIDJSON_SCHEMA_USE_STDREGEX 0 From 0d95d58f8b6259e06e391ce962ec2062260bcdb8 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 13 Jan 2018 12:37:01 +0800 Subject: [PATCH 101/128] Try to fix travis build --- test/unittest/namespacetest.cpp | 4 ++++ test/unittest/unittest.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/test/unittest/namespacetest.cpp b/test/unittest/namespacetest.cpp index 1814724..9f5c9af 100644 --- a/test/unittest/namespacetest.cpp +++ b/test/unittest/namespacetest.cpp @@ -12,6 +12,10 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. +// Not throwing exception for this test +#include +#define RAPIDJSON_ASSERT(x) assert(x) + #include "unittest.h" // test another instantiation of RapidJSON in a different namespace diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index aa091aa..4b1c293 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -117,7 +117,9 @@ public: #pragma GCC diagnostic pop #endif +#ifndef RAPIDJSON_ASSERT #define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u) +#endif class Random { public: From d48290e387932ba016fb1d0117ac4b71edda45ae Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 13 Jan 2018 12:51:24 +0800 Subject: [PATCH 102/128] Another try to fix travis build --- test/unittest/namespacetest.cpp | 4 ---- test/unittest/unittest.h | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/unittest/namespacetest.cpp b/test/unittest/namespacetest.cpp index 9f5c9af..1814724 100644 --- a/test/unittest/namespacetest.cpp +++ b/test/unittest/namespacetest.cpp @@ -12,10 +12,6 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -// Not throwing exception for this test -#include -#define RAPIDJSON_ASSERT(x) assert(x) - #include "unittest.h" // test another instantiation of RapidJSON in a different namespace diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index 4b1c293..84c1b73 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -117,6 +117,9 @@ public: #pragma GCC diagnostic pop #endif +// Not using noexcept for testing RAPIDJSON_ASSERT() +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 + #ifndef RAPIDJSON_ASSERT #define RAPIDJSON_ASSERT(x) (!(x) ? throw AssertException(RAPIDJSON_STRINGIFY(x)) : (void)0u) #endif From fc7cda78a9b25e986f245ed0655df0aa4b71bc3b Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 16 Jan 2018 10:35:19 +0800 Subject: [PATCH 103/128] Fix -Werror=effc++ #1164 --- example/archiver/archiver.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/example/archiver/archiver.h b/example/archiver/archiver.h index c7e74f0..65b31a4 100644 --- a/example/archiver/archiver.h +++ b/example/archiver/archiver.h @@ -89,6 +89,9 @@ public: static const bool IsWriter = !IsReader; private: + JsonReader(const JsonReader&); + JsonReader& operator=(const JsonReader&); + void Next(); // PIMPL @@ -131,6 +134,9 @@ public: static const bool IsWriter = !IsReader; private: + JsonWriter(const JsonWriter&); + JsonWriter& operator=(const JsonWriter&); + // PIMPL idiom void* mWriter; ///< JSON writer. void* mStream; ///< Stream buffer. From 672e7dd3732417971e41c0a3d0161e43d1b37db3 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 12 Feb 2018 10:16:27 +0800 Subject: [PATCH 104/128] Fix invalid type in Pointer Fixed https://github.com/miloyip/rapidjson-gitbook/issues/1 --- include/rapidjson/pointer.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h index 217e71c..8bcb85e 100644 --- a/include/rapidjson/pointer.h +++ b/include/rapidjson/pointer.h @@ -537,14 +537,14 @@ public: */ ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; - Value& v = Create(root, allocator, &alreadyExist); + ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); } //! Query a value in a subtree with default null-terminated string. ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; - Value& v = Create(root, allocator, &alreadyExist); + ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } @@ -552,7 +552,7 @@ public: //! Query a value in a subtree with default std::basic_string. ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; - Value& v = Create(root, allocator, &alreadyExist); + ValueType& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #endif From 82b5c425676d2b07e88c1a8d243ea8284cc21a1d Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 12 Feb 2018 13:14:59 +0800 Subject: [PATCH 105/128] Fix Compile error because of -Werror=effc++ is on Fix #1170 Also fixed C++03 problem for using nullptr. --- example/archiver/archiver.h | 2 +- example/archiver/archivertest.cpp | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/example/archiver/archiver.h b/example/archiver/archiver.h index 65b31a4..2150367 100644 --- a/example/archiver/archiver.h +++ b/example/archiver/archiver.h @@ -74,7 +74,7 @@ public: bool HasMember(const char* name) const; JsonReader& EndObject(); - JsonReader& StartArray(size_t* size = nullptr); + JsonReader& StartArray(size_t* size = 0); JsonReader& EndArray(); JsonReader& operator&(bool& b); diff --git a/example/archiver/archivertest.cpp b/example/archiver/archivertest.cpp index 788db36..16afa1e 100644 --- a/example/archiver/archivertest.cpp +++ b/example/archiver/archivertest.cpp @@ -6,6 +6,11 @@ // Test1: simple object struct Student { + Student() : name(), age(), height(), canSwim() {} + Student(const std::string name, unsigned age, double height, bool canSwim) : + name(name), age(age), height(height), canSwim(canSwim) + {} + std::string name; unsigned age; double height; @@ -31,7 +36,7 @@ void test1() { // Serialize { - Student s = { "Lua", 9, 150.5, true }; + Student s("Lua", 9, 150.5, true); JsonWriter writer; writer & s; @@ -54,6 +59,7 @@ void test1() { // You can map a JSON array to other data structures as well struct Group { + Group() : groupName(), students() {} std::string groupName; std::vector students; }; @@ -124,7 +130,7 @@ public: virtual void Print(std::ostream& os) const = 0; protected: - Shape() {} + Shape() : x_(), y_() {} Shape(double x, double y) : x_(x), y_(y) {} template @@ -142,7 +148,7 @@ Archiver& operator&(Archiver& ar, Shape& s) { class Circle : public Shape { public: - Circle() {} + Circle() : radius_() {} Circle(double x, double y, double radius) : Shape(x, y), radius_(radius) {} ~Circle() {} @@ -168,7 +174,7 @@ Archiver& operator&(Archiver& ar, Circle& c) { class Box : public Shape { public: - Box() {} + Box() : width_(), height_() {} Box(double x, double y, double width, double height) : Shape(x, y), width_(width), height_(height) {} ~Box() {} @@ -195,7 +201,7 @@ Archiver& operator&(Archiver& ar, Box& b) { class Canvas { public: - Canvas() {} + Canvas() : shapes_() {} ~Canvas() { Clear(); } void Clear() { From e2d0437a9cd6f73612b155bd4e4150c66a64c678 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 12 Feb 2018 17:38:46 +0800 Subject: [PATCH 106/128] Fix false alarm from clang-tidy Fix #1174 --- include/rapidjson/internal/stack.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 5c5398c..89558d0 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -100,7 +100,7 @@ public: void ShrinkToFit() { if (Empty()) { // If the stack is empty, completely deallocate the memory. - Allocator::Free(stack_); + Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc) stack_ = 0; stackTop_ = 0; stackEnd_ = 0; From 966987625c4e8f9bc5adce73b9557be128c27be8 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 13 Feb 2018 10:58:41 +0800 Subject: [PATCH 107/128] Add transcoding/validation to Writer::RawValue() Fix #1152 --- include/rapidjson/writer.h | 11 ++++++++--- test/unittest/writertest.cpp | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index e610ebb..a978891 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -460,9 +460,14 @@ protected: bool WriteRawValue(const Ch* json, size_t length) { PutReserve(*os_, length); - for (size_t i = 0; i < length; i++) { - RAPIDJSON_ASSERT(json[i] != '\0'); - PutUnsafe(*os_, json[i]); + GenericStringStream is(json); + while (RAPIDJSON_LIKELY(is.Tell() < length)) { + const Ch c = is.Peek(); + RAPIDJSON_ASSERT(c != '\0'); + if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; } return true; } diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index b190c6c..232b03d 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -538,6 +538,43 @@ TEST(Writer, RawValue) { EXPECT_STREQ("{\"a\":1,\"raw\":[\"Hello\\nWorld\", 123.456]}", buffer.GetString()); } +TEST(Write, RawValue_Issue1152) { + { + GenericStringBuffer > sb; + Writer >, UTF8<>, UTF32<> > writer(sb); + writer.RawValue("null", 4, kNullType); + EXPECT_TRUE(writer.IsComplete()); + const unsigned *out = sb.GetString(); + EXPECT_EQ(static_cast('n'), out[0]); + EXPECT_EQ(static_cast('u'), out[1]); + EXPECT_EQ(static_cast('l'), out[2]); + EXPECT_EQ(static_cast('l'), out[3]); + EXPECT_EQ(static_cast(0 ), out[4]); + } + + { + GenericStringBuffer > sb; + Writer >, UTF16<>, UTF8<> > writer(sb); + writer.RawValue(L"null", 4, kNullType); + EXPECT_TRUE(writer.IsComplete()); + EXPECT_STREQ("null", sb.GetString()); + } + + { + // Fail in transcoding + GenericStringBuffer > buffer; + Writer >, UTF8<>, UTF16<> > writer(buffer); + EXPECT_FALSE(writer.RawValue("\"\xfe\"", 3, kStringType)); + } + + { + // Fail in encoding validation + StringBuffer buffer; + Writer, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer); + EXPECT_FALSE(writer.RawValue("\"\xfe\"", 3, kStringType)); + } +} + #if RAPIDJSON_HAS_CXX11_RVALUE_REFS static Writer WriterGen(StringBuffer &target) { Writer writer(target); From 0d2580f1f0a24d24c0e015d01fc9567a7365ce7e Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 13 Feb 2018 12:20:05 +0800 Subject: [PATCH 108/128] Fix API constness Fix #1014 --- include/rapidjson/document.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index eb6d7dc..269eb65 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1300,7 +1300,7 @@ public: \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ - GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { + GenericValue& AddMember(GenericValue& name, const std::basic_string& value, Allocator& allocator) { GenericValue v(value, allocator); return AddMember(name, v, allocator); } From 59181a052ff5e9fcead6c120945d666bbce8a9b1 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 13 Feb 2018 12:27:25 +0800 Subject: [PATCH 109/128] Revert "Fix API constness" This reverts commit 0d2580f1f0a24d24c0e015d01fc9567a7365ce7e. --- include/rapidjson/document.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 269eb65..eb6d7dc 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1300,7 +1300,7 @@ public: \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ - GenericValue& AddMember(GenericValue& name, const std::basic_string& value, Allocator& allocator) { + GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { GenericValue v(value, allocator); return AddMember(name, v, allocator); } From 49562271be469c8a3ed54ee2d937693a7942b7f3 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Tue, 13 Feb 2018 15:08:20 +0800 Subject: [PATCH 110/128] Fix Windows build --- example/archiver/archivertest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/archiver/archivertest.cpp b/example/archiver/archivertest.cpp index 16afa1e..417a421 100644 --- a/example/archiver/archivertest.cpp +++ b/example/archiver/archivertest.cpp @@ -98,8 +98,8 @@ void test2() { Group g; g.groupName = "Rainbow"; - Student s1 = { "Lua", 9, 150.5, true }; - Student s2 = { "Mio", 7, 120.0, false }; + Student s1("Lua", 9, 150.5, true); + Student s2("Mio", 7, 120.0, false); g.students.push_back(s1); g.students.push_back(s2); From 915218878afb3a60f343a80451723d023273081c Mon Sep 17 00:00:00 2001 From: "luz.paz" Date: Mon, 19 Feb 2018 06:42:52 -0500 Subject: [PATCH 111/128] Misc. typos Found via `codespell -q 3` in downstream https://github.com/BlueBrain/Brayns --- CMakeLists.txt | 2 +- doc/Doxyfile.in | 2 +- doc/Doxyfile.zh-cn.in | 2 +- doc/faq.md | 2 +- doc/internals.md | 4 ++-- example/archiver/archiver.h | 2 +- example/jsonx/jsonx.cpp | 2 +- example/parsebyparts/parsebyparts.cpp | 2 +- include/rapidjson/document.h | 2 +- include/rapidjson/prettywriter.h | 2 +- include/rapidjson/rapidjson.h | 8 ++++---- include/rapidjson/reader.h | 6 +++--- rapidjson.autopkg | 2 +- test/perftest/misctest.cpp | 4 ++-- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c825beb..7c60407 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,7 +128,7 @@ IF(UNIX OR CYGWIN) ELSEIF(WIN32) SET(_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/cmake") ENDIF() -SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake fiels are installed in") +SET(CMAKE_INSTALL_DIR "${_CMAKE_INSTALL_DIR}" CACHE PATH "The directory cmake files are installed in") include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index ca14233..6e79f93 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -1126,7 +1126,7 @@ HTML_STYLESHEET = # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. +# standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. diff --git a/doc/Doxyfile.zh-cn.in b/doc/Doxyfile.zh-cn.in index e7fffa6..6a08f72 100644 --- a/doc/Doxyfile.zh-cn.in +++ b/doc/Doxyfile.zh-cn.in @@ -1126,7 +1126,7 @@ HTML_STYLESHEET = # defined cascading style sheet that is included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. +# standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet file to the output directory. For an example # see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. diff --git a/doc/faq.md b/doc/faq.md index d5697ff..1d738c0 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -236,7 +236,7 @@ Alternatively, if we don't want to explicitly refer to the root value of `addres 4. What is BOM? How RapidJSON handle it? - [Byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark) sometimes reside at the beginning of file/stream to indiciate the UTF encoding type of it. + [Byte order mark (BOM)](http://en.wikipedia.org/wiki/Byte_order_mark) sometimes reside at the beginning of file/stream to indicate the UTF encoding type of it. RapidJSON's `EncodedInputStream` can detect/consume BOM. `EncodedOutputStream` can optionally write a BOM. See [Encoded Streams](doc/stream.md) for example. diff --git a/doc/internals.md b/doc/internals.md index 9b94d7f..706f98c 100644 --- a/doc/internals.md +++ b/doc/internals.md @@ -28,7 +28,7 @@ Both SAX and DOM APIs depends on 3 additional concepts: `Allocator`, `Encoding` ## Data Layout {#DataLayout} -`Value` is a [variant type](http://en.wikipedia.org/wiki/Variant_type). In RapidJSON's context, an instance of `Value` can contain 1 of 6 JSON value types. This is possible by using `union`. Each `Value` contains two members: `union Data data_` and a`unsigned flags_`. The `flags_` indiciates the JSON type, and also additional information. +`Value` is a [variant type](http://en.wikipedia.org/wiki/Variant_type). In RapidJSON's context, an instance of `Value` can contain 1 of 6 JSON value types. This is possible by using `union`. Each `Value` contains two members: `union Data data_` and a`unsigned flags_`. The `flags_` indicates the JSON type, and also additional information. The following tables show the data layout of each type. The 32-bit/64-bit columns indicates the size of the field in bytes. @@ -101,7 +101,7 @@ The following tables show the data layout of each type. The 32-bit/64-bit column Here are some notes: * To reduce memory consumption for 64-bit architecture, `SizeType` is typedef as `unsigned` instead of `size_t`. -* Zero padding for 32-bit number may be placed after or before the actual type, according to the endianess. This makes possible for interpreting a 32-bit integer as a 64-bit integer, without any conversion. +* Zero padding for 32-bit number may be placed after or before the actual type, according to the endianness. This makes possible for interpreting a 32-bit integer as a 64-bit integer, without any conversion. * An `Int` is always an `Int64`, but the converse is not always true. ## Flags {#Flags} diff --git a/example/archiver/archiver.h b/example/archiver/archiver.h index 2150367..285ca73 100644 --- a/example/archiver/archiver.h +++ b/example/archiver/archiver.h @@ -97,7 +97,7 @@ private: // PIMPL void* mDocument; ///< DOM result of parsing. void* mStack; ///< Stack for iterating the DOM - bool mError; ///< Whether an error is occured. + bool mError; ///< Whether an error has occurred. }; class JsonWriter { diff --git a/example/jsonx/jsonx.cpp b/example/jsonx/jsonx.cpp index 1346b57..954aa2b 100644 --- a/example/jsonx/jsonx.cpp +++ b/example/jsonx/jsonx.cpp @@ -1,4 +1,4 @@ -// JSON to JSONx conversion exmaple, using SAX API. +// JSON to JSONx conversion example, using SAX API. // JSONx is an IBM standard format to represent JSON as XML. // https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html // This example parses JSON text from stdin with validation, diff --git a/example/parsebyparts/parsebyparts.cpp b/example/parsebyparts/parsebyparts.cpp index a377efd..ff73539 100644 --- a/example/parsebyparts/parsebyparts.cpp +++ b/example/parsebyparts/parsebyparts.cpp @@ -143,7 +143,7 @@ int main() { AsyncDocumentParser<> parser(d); const char json1[] = " { \"hello\" : \"world\", \"t\" : tr"; - //const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // Fot test parsing error + //const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // For test parsing error const char json2[] = "ue, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.14"; const char json3[] = "16, \"a\":[1, 2, 3, 4] } "; diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index eb6d7dc..ba169cf 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2362,7 +2362,7 @@ public: //!@name Handling parse errors //!@{ - //! Whether a parse error has occured in the last parsing. + //! Whether a parse error has occurred in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index 98dfb30..95bb6ff 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -39,7 +39,7 @@ enum PrettyFormatOptions { //! Writer with indentation and spacing. /*! - \tparam OutputStream Type of ouptut os. + \tparam OutputStream Type of output os. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 5716fdc..98332fa 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -26,7 +26,7 @@ Some RapidJSON features are configurable to adapt the library to a wide variety of platforms, environments and usage scenarios. Most of the - features can be configured in terms of overriden or predefined + features can be configured in terms of overridden or predefined preprocessor macros at compile-time. Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. @@ -219,7 +219,7 @@ # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif // __BYTE_ORDER__ // Detect with GLIBC's endian.h # elif defined(__GLIBC__) @@ -229,7 +229,7 @@ # elif (__BYTE_ORDER == __BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif // __GLIBC__ // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro # elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) @@ -246,7 +246,7 @@ # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN # else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. # endif #endif // RAPIDJSON_ENDIAN diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 681dec2..084efaa 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -678,7 +678,7 @@ public: return IsIterativeParsingCompleteState(state_); } - //! Whether a parse error has occured in the last parsing. + //! Whether a parse error has occurred in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. @@ -901,7 +901,7 @@ private: return false; } - // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). + // Helper function to parse four hexadecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(InputStream& is, size_t escapeOffset) { unsigned codepoint = 0; @@ -1008,7 +1008,7 @@ private: Ch c = is.Peek(); if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape - size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset + size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset is.Take(); Ch e = is.Peek(); if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { diff --git a/rapidjson.autopkg b/rapidjson.autopkg index cbe5258..fe72030 100644 --- a/rapidjson.autopkg +++ b/rapidjson.autopkg @@ -48,7 +48,7 @@ Changed dependencies { packages : { - //TODO: Add dependecies here in [pkg.name]/[version] form per newline + //TODO: Add dependencies here in [pkg.name]/[version] form per newline //zlib/[1.2.8], }; } diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp index aac8477..d81062f 100644 --- a/test/perftest/misctest.cpp +++ b/test/perftest/misctest.cpp @@ -432,7 +432,7 @@ bool Writer1::WriteUint(unsigned u) { return true; } -// Using digits LUT to reduce divsion/modulo +// Using digits LUT to reduce division/modulo template class Writer2 { public: @@ -616,7 +616,7 @@ inline bool Writer3::WriteUint64(uint64_t u) { return true; } -// Using digits LUT to reduce divsion/modulo, two passes +// Using digits LUT to reduce division/modulo, two passes template class Writer4 { public: From 54dab1eebb0dea32d9ea49dad4fa9c98816c21ed Mon Sep 17 00:00:00 2001 From: Romain Geissler Date: Mon, 19 Feb 2018 12:52:16 +0100 Subject: [PATCH 112/128] Ignore GCC 8 warnings. --- include/rapidjson/document.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index eb6d7dc..69ac924 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -2014,7 +2014,12 @@ private: if (count) { GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); SetElementsPointer(e); +RAPIDJSON_DIAG_PUSH +#if defined(__GNUC__) && __GNUC__ >= 8 +RAPIDJSON_DIAG_OFF(class-memaccess) // ignore complains from gcc that no trivial copy constructor exists. +#endif std::memcpy(e, values, count * sizeof(GenericValue)); +RAPIDJSON_DIAG_POP } else SetElementsPointer(0); @@ -2027,7 +2032,12 @@ private: if (count) { Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); SetMembersPointer(m); +RAPIDJSON_DIAG_PUSH +#if defined(__GNUC__) && __GNUC__ >= 8 +RAPIDJSON_DIAG_OFF(class-memaccess) // ignore complains from gcc that no trivial copy constructor exists. +#endif std::memcpy(m, members, count * sizeof(Member)); +RAPIDJSON_DIAG_POP } else SetMembersPointer(0); From 72481d5a04d64f70a96a545b714dafac35c84deb Mon Sep 17 00:00:00 2001 From: "maficccc@gmail.com" Date: Sat, 3 Mar 2018 00:08:11 +0100 Subject: [PATCH 113/128] Fix warnings Dereference of null pointer --- include/rapidjson/internal/itoa.h | 79 ++++++++++++++++--------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/include/rapidjson/internal/itoa.h b/include/rapidjson/internal/itoa.h index 01a4e7e..a39accb 100644 --- a/include/rapidjson/internal/itoa.h +++ b/include/rapidjson/internal/itoa.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_ITOA_ @@ -37,12 +37,14 @@ inline const char* GetDigitsLut() { } inline char* u32toa(uint32_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); + const char* cDigitsLut = GetDigitsLut(); if (value < 10000) { const uint32_t d1 = (value / 100) << 1; const uint32_t d2 = (value % 100) << 1; - + if (value >= 1000) *buffer++ = cDigitsLut[d1]; if (value >= 100) @@ -55,13 +57,13 @@ inline char* u32toa(uint32_t value, char* buffer) { // value = bbbbcccc const uint32_t b = value / 10000; const uint32_t c = value % 10000; - + const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; - + const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; - + if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) @@ -69,7 +71,7 @@ inline char* u32toa(uint32_t value, char* buffer) { if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; - + *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; @@ -77,10 +79,10 @@ inline char* u32toa(uint32_t value, char* buffer) { } else { // value = aabbbbcccc in decimal - + const uint32_t a = value / 100000000; // 1 to 42 value %= 100000000; - + if (a >= 10) { const unsigned i = a << 1; *buffer++ = cDigitsLut[i]; @@ -91,13 +93,13 @@ inline char* u32toa(uint32_t value, char* buffer) { const uint32_t b = value / 10000; // 0 to 9999 const uint32_t c = value % 10000; // 0 to 9999 - + const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; - + const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; - + *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; @@ -111,6 +113,7 @@ inline char* u32toa(uint32_t value, char* buffer) { } inline char* i32toa(int32_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); uint32_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; @@ -121,6 +124,7 @@ inline char* i32toa(int32_t value, char* buffer) { } inline char* u64toa(uint64_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); const char* cDigitsLut = GetDigitsLut(); const uint64_t kTen8 = 100000000; const uint64_t kTen9 = kTen8 * 10; @@ -131,13 +135,13 @@ inline char* u64toa(uint64_t value, char* buffer) { const uint64_t kTen14 = kTen8 * 1000000; const uint64_t kTen15 = kTen8 * 10000000; const uint64_t kTen16 = kTen8 * kTen8; - + if (value < kTen8) { uint32_t v = static_cast(value); if (v < 10000) { const uint32_t d1 = (v / 100) << 1; const uint32_t d2 = (v % 100) << 1; - + if (v >= 1000) *buffer++ = cDigitsLut[d1]; if (v >= 100) @@ -150,13 +154,13 @@ inline char* u64toa(uint64_t value, char* buffer) { // value = bbbbcccc const uint32_t b = v / 10000; const uint32_t c = v % 10000; - + const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; - + const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; - + if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) @@ -164,7 +168,7 @@ inline char* u64toa(uint64_t value, char* buffer) { if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; - + *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; @@ -174,22 +178,22 @@ inline char* u64toa(uint64_t value, char* buffer) { else if (value < kTen16) { const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); - + const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; - + const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; - + const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; - + const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; - + const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; @@ -209,7 +213,7 @@ inline char* u64toa(uint64_t value, char* buffer) { *buffer++ = cDigitsLut[d4]; if (value >= kTen8) *buffer++ = cDigitsLut[d4 + 1]; - + *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; @@ -222,7 +226,7 @@ inline char* u64toa(uint64_t value, char* buffer) { else { const uint32_t a = static_cast(value / kTen16); // 1 to 1844 value %= kTen16; - + if (a < 10) *buffer++ = static_cast('0' + static_cast(a)); else if (a < 100) { @@ -232,7 +236,7 @@ inline char* u64toa(uint64_t value, char* buffer) { } else if (a < 1000) { *buffer++ = static_cast('0' + static_cast(a / 100)); - + const uint32_t i = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; @@ -245,28 +249,28 @@ inline char* u64toa(uint64_t value, char* buffer) { *buffer++ = cDigitsLut[j]; *buffer++ = cDigitsLut[j + 1]; } - + const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); - + const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; - + const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; - + const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; - + const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; - + const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; - + const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; - + *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; @@ -284,11 +288,12 @@ inline char* u64toa(uint64_t value, char* buffer) { *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } - + return buffer; } inline char* i64toa(int64_t value, char* buffer) { + RAPIDJSON_ASSERT(buffer != 0); uint64_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; From 294a5aca8f7d84c0bf982c0bf59ffee08acc7ff9 Mon Sep 17 00:00:00 2001 From: MaximeBF Date: Tue, 6 Mar 2018 11:17:04 -0500 Subject: [PATCH 114/128] Support long and unsined long as int and unsigned on Microsft platforms --- include/rapidjson/document.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index f28d8ca..a6acc24 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -451,6 +451,26 @@ struct TypeHelper { static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } }; +#ifdef _MSC_VER +RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static long Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); } +}; + +RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned long Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); } +}; +#endif + template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsInt64(); } From a040fc3347f2ffeca7e4e3c71aefeaa37840af56 Mon Sep 17 00:00:00 2001 From: MaximeBF Date: Thu, 8 Mar 2018 07:28:51 -0500 Subject: [PATCH 115/128] Add unittest for long as int in MSC platforms --- test/unittest/valuetest.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 307e1b0..d59ec1b 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -439,6 +439,14 @@ TEST(Value, Int) { EXPECT_EQ(5678, z.Get()); EXPECT_EQ(5679, z.Set(5679).Get()); EXPECT_EQ(5680, z.Set(5680).Get()); + +#ifdef _MSC_VER + // long as int on MSC platforms + RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); + z.SetInt(1234); + EXPECT_TRUE(z.Is()); + EXPECT_EQ(1234l, z.Get()); +#endif } TEST(Value, Uint) { @@ -485,6 +493,14 @@ TEST(Value, Uint) { EXPECT_EQ(2147483648u, z.Get()); EXPECT_EQ(2147483649u, z.Set(2147483649u).Get()); EXPECT_EQ(2147483650u, z.Set(2147483650u).Get()); + +#ifdef _MSC_VER + // unsigned long as unsigned on MSC platforms + RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); + z.SetUint(1234); + EXPECT_TRUE(z.Is()); + EXPECT_EQ(1234ul, z.Get()); +#endif } TEST(Value, Int64) { From a37f9d1ecd62e65cc5b9b0a9d04d223c6cd76429 Mon Sep 17 00:00:00 2001 From: MaximeBF Date: Thu, 8 Mar 2018 07:33:26 -0500 Subject: [PATCH 116/128] Fix unsigned long as unsigned unit test --- test/unittest/valuetest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index d59ec1b..0e2cf8e 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -499,7 +499,7 @@ TEST(Value, Uint) { RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); z.SetUint(1234); EXPECT_TRUE(z.Is()); - EXPECT_EQ(1234ul, z.Get()); + EXPECT_EQ(1234ul, z.Get()); #endif } From 2e5dcceda085854a034520bc485365e8c5f9acc2 Mon Sep 17 00:00:00 2001 From: sergey kachanovskiy Date: Mon, 12 Mar 2018 16:11:09 +0100 Subject: [PATCH 117/128] Fixes #1198 --- include/rapidjson/schema.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 1a8fb26..aefdd95 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -1860,7 +1860,12 @@ public: //! Gets the JSON pointer pointed to the invalid value. PointerType GetInvalidDocumentPointer() const { - return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + if (documentStack_.Empty()) { + return PointerType(); + } + else { + return PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + } } void NotMultipleOf(int64_t actual, const SValue& expected) { From 27424d5c092104e1d481140ac008745bb24b7ae0 Mon Sep 17 00:00:00 2001 From: MaximeBF Date: Wed, 14 Mar 2018 08:44:00 -0400 Subject: [PATCH 118/128] Change long/ulong as int/uint on MSC unit tests to be more inline with other templated functions unit tests --- test/unittest/valuetest.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 0e2cf8e..0eea92a 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -443,9 +443,12 @@ TEST(Value, Int) { #ifdef _MSC_VER // long as int on MSC platforms RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int)); - z.SetInt(1234); + z.SetInt(2222); EXPECT_TRUE(z.Is()); - EXPECT_EQ(1234l, z.Get()); + EXPECT_EQ(2222l, z.Get()); + EXPECT_EQ(3333l, z.Set(3333l).Get()); + EXPECT_EQ(4444l, z.Set(4444l).Get()); + EXPECT_TRUE(z.IsInt()); #endif } @@ -497,9 +500,12 @@ TEST(Value, Uint) { #ifdef _MSC_VER // unsigned long as unsigned on MSC platforms RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned)); - z.SetUint(1234); + z.SetUint(2222); EXPECT_TRUE(z.Is()); - EXPECT_EQ(1234ul, z.Get()); + EXPECT_EQ(2222ul, z.Get()); + EXPECT_EQ(3333ul, z.Set(3333ul).Get()); + EXPECT_EQ(4444ul, z.Set(4444ul).Get()); + EXPECT_TRUE(x.IsUint()); #endif } From f9c9339761d3b3a5584e64b2219d4344ff5a8394 Mon Sep 17 00:00:00 2001 From: KLsz Date: Fri, 16 Mar 2018 23:50:17 +0800 Subject: [PATCH 119/128] Adding a few missing includes --- doc/stream.md | 3 +++ doc/stream.zh-cn.md | 3 +++ 2 files changed, 6 insertions(+) diff --git a/doc/stream.md b/doc/stream.md index b79ce53..d95de14 100644 --- a/doc/stream.md +++ b/doc/stream.md @@ -42,6 +42,7 @@ Note that, `StringStream` is a typedef of `GenericStringStream >`, user m ~~~~~~~~~~cpp #include "rapidjson/stringbuffer.h" +#include StringBuffer buffer; Writer writer(buffer); @@ -98,6 +99,7 @@ Apart from reading file, user can also use `FileReadStream` to read `stdin`. ~~~~~~~~~~cpp #include "rapidjson/filewritestream.h" +#include #include using namespace rapidjson; @@ -215,6 +217,7 @@ fclose(fp); ~~~~~~~~~~cpp #include "rapidjson/filewritestream.h" // FileWriteStream #include "rapidjson/encodedstream.h" // EncodedOutputStream +#include #include Document d; // Document is GenericDocument > diff --git a/doc/stream.zh-cn.md b/doc/stream.zh-cn.md index f2c54f7..7f2f356 100644 --- a/doc/stream.zh-cn.md +++ b/doc/stream.zh-cn.md @@ -42,6 +42,7 @@ d.Parse(json); ~~~~~~~~~~cpp #include "rapidjson/stringbuffer.h" +#include StringBuffer buffer; Writer writer(buffer); @@ -98,6 +99,7 @@ fclose(fp); ~~~~~~~~~~cpp #include "rapidjson/filewritestream.h" +#include #include using namespace rapidjson; @@ -215,6 +217,7 @@ fclose(fp); ~~~~~~~~~~cpp #include "rapidjson/filewritestream.h" // FileWriteStream #include "rapidjson/encodedstream.h" // EncodedOutputStream +#include #include Document d; // Document 为 GenericDocument > From de6681e295726f528a4b449ca51c940972eb6f1a Mon Sep 17 00:00:00 2001 From: John Date: Mon, 19 Mar 2018 15:18:08 -0400 Subject: [PATCH 120/128] ensure the pragma is only applied to MSVC --- include/rapidjson/internal/biginteger.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/internal/biginteger.h b/include/rapidjson/internal/biginteger.h index 9d3e88c..f936a10 100644 --- a/include/rapidjson/internal/biginteger.h +++ b/include/rapidjson/internal/biginteger.h @@ -17,7 +17,7 @@ #include "../rapidjson.h" -#if defined(_MSC_VER) && defined(_M_AMD64) +#if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64) #include // for _umul128 #pragma intrinsic(_umul128) #endif From 8a6c345bcc58b1e1e96ac0cddf42ca373fcf13bd Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 23 Mar 2018 23:33:20 +0100 Subject: [PATCH 121/128] add remote ref to schemaMap_ --- include/rapidjson/schema.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index aefdd95..35748cc 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -1673,6 +1673,7 @@ private: if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { if (schema) *schema = sc; + new (schemaMap_.template Push()) SchemaEntry(source, const_cast(sc), false, allocator_); return true; } } From c8530d022fdc5a72ec15f0e7e7a1f330b1cd8710 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Mon, 26 Mar 2018 13:04:35 +0200 Subject: [PATCH 122/128] add test case for remote ref issue --- test/unittest/schematest.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 121d386..951e9ff 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -2004,6 +2004,35 @@ TEST(SchemaValidator, Ref_remote) { SchemaValidatorType, PointerType); } +TEST(SchemaValidator, Ref_remote_issue1210) { + class SchemaDocumentProvider : public IRemoteSchemaDocumentProvider { + SchemaDocument** collection; + public: + SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { } + virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) { + int i = 0; + while (collection[i] && typename SchemaDocument::URIType(uri, length) != collection[i]->GetURI()) ++i; + return collection[i]; + } + }; + SchemaDocument* collection[] { 0, 0, 0 }; + SchemaDocumentProvider provider(collection); + + Document x, y, z; + x.Parse("{\"properties\":{\"country\":{\"$ref\":\"y.json#/definitions/country_remote\"}},\"type\":\"object\"}"); + y.Parse("{\"definitions\":{\"country_remote\":{\"$ref\":\"z.json#/definitions/country_list\"}}}"); + z.Parse("{\"definitions\":{\"country_list\":{\"enum\":[\"US\"]}}}"); + + SchemaDocument sz(z, "z.json", 6, &provider); + collection[0] = &sz; + SchemaDocument sy(y, "y.json", 6, &provider); + collection[1] = &sy; + SchemaDocument sx(x, "x.json", 6, &provider); + + VALIDATE(sx, "{\"country\":\"UK\"}", false); + VALIDATE(sx, "{\"country\":\"US\"}", true); +} + #ifdef __clang__ RAPIDJSON_DIAG_POP #endif From f8c8c32b42ee9db055f325252d6f6fc57a34fdf5 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Mon, 26 Mar 2018 13:16:31 +0200 Subject: [PATCH 123/128] fix C++03 compatibility --- test/unittest/schematest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 951e9ff..9c78add 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -2015,7 +2015,7 @@ TEST(SchemaValidator, Ref_remote_issue1210) { return collection[i]; } }; - SchemaDocument* collection[] { 0, 0, 0 }; + SchemaDocument* collection[] = { 0, 0, 0 }; SchemaDocumentProvider provider(collection); Document x, y, z; From 9640209f789bfd2f670ee7de4bfec92e94048f0e Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Mon, 26 Mar 2018 13:29:52 +0200 Subject: [PATCH 124/128] remove superfluous typename --- test/unittest/schematest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 9c78add..8cf1c68 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -2011,7 +2011,7 @@ TEST(SchemaValidator, Ref_remote_issue1210) { SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { } virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) { int i = 0; - while (collection[i] && typename SchemaDocument::URIType(uri, length) != collection[i]->GetURI()) ++i; + while (collection[i] && SchemaDocument::URIType(uri, length) != collection[i]->GetURI()) ++i; return collection[i]; } }; From 0fdd8040ce4eec4522e62a955de00cf8a9a4f66b Mon Sep 17 00:00:00 2001 From: Zoltan Kovago Date: Fri, 6 Apr 2018 18:38:52 +0200 Subject: [PATCH 125/128] fix compilation on windows with clang --- include/rapidjson/document.h | 8 +++----- include/rapidjson/encodings.h | 4 ++-- include/rapidjson/internal/meta.h | 9 +++++++-- include/rapidjson/internal/regex.h | 12 +++++------- include/rapidjson/istreamwrapper.h | 4 +--- include/rapidjson/pointer.h | 10 ++-------- include/rapidjson/rapidjson.h | 2 +- include/rapidjson/reader.h | 16 +++++----------- include/rapidjson/schema.h | 4 +--- include/rapidjson/writer.h | 14 ++++---------- test/unittest/istreamwrappertest.cpp | 4 ++-- test/unittest/schematest.cpp | 9 ++++++++- 12 files changed, 41 insertions(+), 55 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index a6acc24..d25c5c0 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -26,15 +26,13 @@ #include RAPIDJSON_DIAG_PUSH -#ifdef _MSC_VER -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data -#endif - #ifdef __clang__ RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data #endif #ifdef __GNUC__ diff --git a/include/rapidjson/encodings.h b/include/rapidjson/encodings.h index 7903e76..12b562a 100644 --- a/include/rapidjson/encodings.h +++ b/include/rapidjson/encodings.h @@ -17,7 +17,7 @@ #include "rapidjson.h" -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data RAPIDJSON_DIAG_OFF(4702) // unreachable code @@ -709,7 +709,7 @@ struct Transcoder { RAPIDJSON_NAMESPACE_END -#if defined(__GNUC__) || defined(_MSC_VER) +#if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__)) RAPIDJSON_DIAG_POP #endif diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h index 5a9aaa4..d401edf 100644 --- a/include/rapidjson/internal/meta.h +++ b/include/rapidjson/internal/meta.h @@ -21,7 +21,8 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif -#if defined(_MSC_VER) + +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(6334) #endif @@ -174,7 +175,11 @@ template struct RemoveSfinaeTag { typedef T Type; RAPIDJSON_NAMESPACE_END //@endcond -#if defined(__GNUC__) || defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + +#ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif diff --git a/include/rapidjson/internal/regex.h b/include/rapidjson/internal/regex.h index e1a2faa..de06718 100644 --- a/include/rapidjson/internal/regex.h +++ b/include/rapidjson/internal/regex.h @@ -24,6 +24,9 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif #ifdef __GNUC__ @@ -34,11 +37,6 @@ RAPIDJSON_DIAG_OFF(implicit-fallthrough) #endif #endif -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated -#endif - #ifndef RAPIDJSON_REGEX_VERBOSE #define RAPIDJSON_REGEX_VERBOSE 0 #endif @@ -723,11 +721,11 @@ typedef GenericRegexSearch RegexSearch; } // namespace internal RAPIDJSON_NAMESPACE_END -#ifdef __clang__ +#ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif -#ifdef _MSC_VER +#if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif diff --git a/include/rapidjson/istreamwrapper.h b/include/rapidjson/istreamwrapper.h index 8639c8c..5f81698 100644 --- a/include/rapidjson/istreamwrapper.h +++ b/include/rapidjson/istreamwrapper.h @@ -21,9 +21,7 @@ #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) -#endif - -#ifdef _MSC_VER +#elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized #endif diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h index 8bcb85e..3d339f2 100644 --- a/include/rapidjson/pointer.h +++ b/include/rapidjson/pointer.h @@ -21,9 +21,7 @@ #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(switch-enum) -#endif - -#ifdef _MSC_VER +#elif defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif @@ -1352,11 +1350,7 @@ bool EraseValueByPointer(T& root, const CharType(&source)[N]) { RAPIDJSON_NAMESPACE_END -#ifdef __clang__ -RAPIDJSON_DIAG_POP -#endif - -#ifdef _MSC_VER +#if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 98332fa..be30776 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -433,7 +433,7 @@ template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; template struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END -#if defined(__GNUC__) +#if defined(__GNUC__) || defined(__clang__) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 084efaa..e6a696c 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -37,17 +37,15 @@ #include #endif -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -RAPIDJSON_DIAG_OFF(4702) // unreachable code -#endif - #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(old-style-cast) RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant +RAPIDJSON_DIAG_OFF(4702) // unreachable code #endif #ifdef __GNUC__ @@ -2206,7 +2204,7 @@ typedef GenericReader, UTF8<> > Reader; RAPIDJSON_NAMESPACE_END -#ifdef __clang__ +#if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif @@ -2215,8 +2213,4 @@ RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP #endif -#ifdef _MSC_VER -RAPIDJSON_DIAG_POP -#endif - #endif // RAPIDJSON_READER_H_ diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 35748cc..d8caf9b 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -63,9 +63,7 @@ RAPIDJSON_DIAG_OFF(weak-vtables) RAPIDJSON_DIAG_OFF(exit-time-destructors) RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) RAPIDJSON_DIAG_OFF(variadic-macros) -#endif - -#ifdef _MSC_VER +#elif defined(_MSC_VER) RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index a978891..49cc0fb 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -36,16 +36,14 @@ #include #endif -#ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH -RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -#endif - #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(c++98-compat) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif RAPIDJSON_NAMESPACE_BEGIN @@ -705,11 +703,7 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz RAPIDJSON_NAMESPACE_END -#ifdef _MSC_VER -RAPIDJSON_DIAG_POP -#endif - -#ifdef __clang__ +#if defined(_MSC_VER) || defined(__clang__) RAPIDJSON_DIAG_POP #endif diff --git a/test/unittest/istreamwrappertest.cpp b/test/unittest/istreamwrappertest.cpp index 9d6fbcf..94480cd 100644 --- a/test/unittest/istreamwrappertest.cpp +++ b/test/unittest/istreamwrappertest.cpp @@ -20,7 +20,7 @@ #include #include -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4702) // unreachable code #endif @@ -176,6 +176,6 @@ TEST(IStreamWrapper, wfstream) { #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) && !defined(__clang__) RAPIDJSON_DIAG_POP #endif diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 8cf1c68..c64bf78 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -20,6 +20,9 @@ #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(variadic-macros) +#elif defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4822) // local class member function does not have a body #endif using namespace rapidjson; @@ -2007,6 +2010,10 @@ TEST(SchemaValidator, Ref_remote) { TEST(SchemaValidator, Ref_remote_issue1210) { class SchemaDocumentProvider : public IRemoteSchemaDocumentProvider { SchemaDocument** collection; + + SchemaDocumentProvider(const SchemaDocumentProvider&); + SchemaDocumentProvider& operator=(const SchemaDocumentProvider&); + public: SchemaDocumentProvider(SchemaDocument** collection) : collection(collection) { } virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) { @@ -2033,6 +2040,6 @@ TEST(SchemaValidator, Ref_remote_issue1210) { VALIDATE(sx, "{\"country\":\"US\"}", true); } -#ifdef __clang__ +#if defined(_MSC_VER) || defined(__clang__) RAPIDJSON_DIAG_POP #endif From 6f587466a1b714fea392423cf3507fcd0f2b546e Mon Sep 17 00:00:00 2001 From: Ryan Morris Date: Tue, 17 Apr 2018 12:53:23 -0700 Subject: [PATCH 126/128] Added macro RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY to allow default chunk capacity to be lowered for embedded devices with < 64k stack sizes --- include/rapidjson/allocators.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h index 655f4a3..06b3420 100644 --- a/include/rapidjson/allocators.h +++ b/include/rapidjson/allocators.h @@ -52,6 +52,19 @@ concept Allocator { \endcode */ + +/*! \def RAPIDJSON_ALLOCATOR_DEFUALT_CHUNK_CAPACITY + \ingroup RAPIDJSON_CONFIG + \brief User-defined kDefaultChunkCapacity definition. + + User can define this as any \c size that is a power of 2. +*/ + +#ifndef RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY +#define RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024) +#endif + + /////////////////////////////////////////////////////////////////////////////// // CrtAllocator @@ -248,7 +261,7 @@ private: return false; } - static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. + static const int kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. //! Chunk header for perpending to each chunk. /*! Chunks are stored as a singly linked list. From 73b8774ab16c6474c4759853059fdfdf7559b5c9 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Tue, 24 Apr 2018 22:55:47 +0100 Subject: [PATCH 127/128] Use rvalue refs with clang-cl --- include/rapidjson/rapidjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index 98332fa..aa3de99 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -543,7 +543,7 @@ RAPIDJSON_NAMESPACE_END #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS #if defined(__clang__) #if __has_feature(cxx_rvalue_references) && \ - (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) + (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 From d0a78bf56e57f9813224523700818ca385209ab6 Mon Sep 17 00:00:00 2001 From: Sergey Kovalevich Date: Thu, 3 May 2018 15:11:16 +0300 Subject: [PATCH 128/128] Added const for Reader methods --- include/rapidjson/reader.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 120c311..c4278ae 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -673,7 +673,7 @@ public: //! Check if token-by-token parsing JSON text is complete /*! \return Whether the JSON has been fully decoded. */ - RAPIDJSON_FORCEINLINE bool IterativeParseComplete() { + RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const { return IsIterativeParsingCompleteState(state_); } @@ -1785,7 +1785,7 @@ private: kTokenCount }; - RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define N NumberToken @@ -1812,7 +1812,7 @@ private: return NumberToken; } - RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { + RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const { // current state x one lookahead token -> new state static const char G[cIterativeParsingStateCount][kTokenCount] = { // Finish(sink state) @@ -2151,11 +2151,11 @@ private: } } - RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) { + RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const { return s >= IterativeParsingElementDelimiterState; } - RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) { + RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const { return s <= IterativeParsingErrorState; }