From: subhransu mohanty Date: Wed, 5 Jun 2019 01:53:54 +0000 (+0900) Subject: rlottie/json: updated to latest rapidjson X-Git-Tag: submit/tizen/20190619.051039~9 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9c716fdfec1f7d1c937306ac2be4ea5b896654ba;p=platform%2Fcore%2Fuifw%2Flottie-player.git rlottie/json: updated to latest rapidjson --- diff --git a/src/lottie/rapidjson/allocators.h b/src/lottie/rapidjson/allocators.h index 655f4a3..cc67c89 100644 --- a/src/lottie/rapidjson/allocators.h +++ b/src/lottie/rapidjson/allocators.h @@ -52,6 +52,19 @@ concept Allocator { \endcode */ + +/*! \def RAPIDJSON_ALLOCATOR_DEFAULT_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. diff --git a/src/lottie/rapidjson/document.h b/src/lottie/rapidjson/document.h index 98c4eb1..d1b90eb 100644 --- a/src/lottie/rapidjson/document.h +++ b/src/lottie/rapidjson/document.h @@ -26,26 +26,21 @@ #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__ RAPIDJSON_DIAG_OFF(effc++) -#if __GNUC__ >= 6 -RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions -#endif #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 @@ -71,6 +66,12 @@ template struct GenericMember { GenericValue name; //!< name of member (must be a string) GenericValue value; //!< value of member. + + // swap() for std::sort() and other potential use in STL. + friend inline void swap(GenericMember& a, GenericMember& b) RAPIDJSON_NOEXCEPT { + a.name.Swap(b.name); + a.value.Swap(b.value); + } }; /////////////////////////////////////////////////////////////////////////////// @@ -98,16 +99,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 +115,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. @@ -445,6 +452,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(); } @@ -601,11 +628,11 @@ public: \note Default content for number is zero. */ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { - static const uint16_t defaultFlags[7] = { + static const uint16_t defaultFlags[] = { kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; - RAPIDJSON_ASSERT(type >= kNullType && type <= kNumberType); + RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType); data_.f.flags = defaultFlags[type]; // Use ShortString to store empty string. @@ -807,9 +834,10 @@ public: /*! \param rhs Source of the assignment. It will become a null value after assignment. */ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { - RAPIDJSON_ASSERT(this != &rhs); - this->~GenericValue(); - RawAssign(rhs); + if (RAPIDJSON_LIKELY(this != &rhs)) { + this->~GenericValue(); + RawAssign(rhs); + } return *this; } @@ -901,7 +929,7 @@ public: //! Equal-to operator /*! \note If an object contains duplicated named member, comparing equality with any object is always \c false. - \note Linear time complexity (number of all values in the subtree and total lengths of all strings). + \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings). */ template bool operator==(const GenericValue& rhs) const { @@ -1090,25 +1118,6 @@ public: GenericValue n(StringRef(name)); return (*this)[n]; } - - template - float optFloat(T* name, float fallback = 0.0) { - GenericValue n(StringRef(name)); - return optFloat(n, fallback); - } - - template - double optDouble(T* name, double fallback = 0.0) { - GenericValue n(StringRef(name)); - return optDouble(n, fallback); - } - - template - int optInt(T* name, int fallback=0) { - GenericValue n(StringRef(name)); - return optInt(n, fallback); - } - template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } @@ -1138,31 +1147,6 @@ public: return *new (buffer) GenericValue(); } } - - template - float optFloat(const GenericValue& name, float fallback) { - MemberIterator member = FindMember(name); - if (member != MemberEnd()) - return member->value.GetFloat(); - return fallback; - } - - template - double optDouble(const GenericValue& name, double fallback) { - MemberIterator member = FindMember(name); - if (member != MemberEnd()) - return member->value.GetDouble(); - return fallback; - } - - template - int optInt(const GenericValue& name, int fallback) { - MemberIterator member = FindMember(name); - if (member != MemberEnd() && member->value.IsInt()) - return member->value.GetInt(); - return fallback; - } - template const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } @@ -1533,7 +1517,7 @@ public: MemberIterator pos = MemberBegin() + (first - MemberBegin()); for (MemberIterator itr = pos; itr != last; ++itr) itr->~Member(); - std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); + std::memmove(static_cast(&*pos), &*last, static_cast(MemberEnd() - last) * sizeof(Member)); data_.o.size -= static_cast(last - first); return pos; } @@ -1736,8 +1720,8 @@ public: RAPIDJSON_ASSERT(last <= End()); ValueIterator pos = Begin() + (first - Begin()); for (ValueIterator itr = pos; itr != last; ++itr) - itr->~GenericValue(); - std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); + itr->~GenericValue(); + std::memmove(static_cast(pos), last, static_cast(End() - last) * sizeof(GenericValue)); data_.a.size -= static_cast(last - first); return pos; } @@ -2052,7 +2036,7 @@ private: if (count) { GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); SetElementsPointer(e); - std::memcpy(e, values, count * sizeof(GenericValue)); + std::memcpy(static_cast(e), values, count * sizeof(GenericValue)); } else SetElementsPointer(0); @@ -2065,7 +2049,7 @@ private: if (count) { Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); SetMembersPointer(m); - std::memcpy(m, members, count * sizeof(Member)); + std::memcpy(static_cast(m), members, count * sizeof(Member)); } else SetMembersPointer(0); @@ -2125,8 +2109,6 @@ private: //! GenericValue with UTF8 encoding typedef GenericValue > Value; -typedef GenericValue > JsonObj; - /////////////////////////////////////////////////////////////////////////////// // GenericDocument @@ -2402,7 +2384,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. @@ -2522,8 +2504,6 @@ private: //! GenericDocument with UTF8 encoding typedef GenericDocument > Document; -typedef GenericDocument > JsonDoc; - //! Helper class for accessing Value of array type. /*! @@ -2547,7 +2527,7 @@ public: GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } - ~GenericArray() = default; + ~GenericArray() {} SizeType Size() const { return value_.Size(); } SizeType Capacity() const { return value_.Capacity(); } @@ -2602,7 +2582,7 @@ public: GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } - ~GenericObject() = default; + ~GenericObject() {} SizeType MemberCount() const { return value_.MemberCount(); } SizeType MemberCapacity() const { return value_.MemberCapacity(); } diff --git a/src/lottie/rapidjson/encodings.h b/src/lottie/rapidjson/encodings.h index 7903e76..0b24467 100644 --- a/src/lottie/rapidjson/encodings.h +++ b/src/lottie/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 @@ -144,9 +144,9 @@ struct UTF8 { template static bool Decode(InputStream& is, unsigned* codepoint) { -#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) -#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define TAIL() COPY(); TRANS(0x70) +#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) +#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) typename InputStream::Ch c = is.Take(); if (!(c & 0x80)) { *codepoint = static_cast(c); @@ -161,44 +161,44 @@ struct UTF8 { } bool result = true; switch (type) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + case 2: RAPIDJSON_TAIL(); return result; + case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; + case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; + case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; default: return false; } -#undef COPY -#undef TRANS -#undef TAIL +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL } template static bool Validate(InputStream& is, OutputStream& os) { -#define COPY() os.Put(c = is.Take()) -#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) -#define TAIL() COPY(); TRANS(0x70) +#define RAPIDJSON_COPY() os.Put(c = is.Take()) +#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) +#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) Ch c; - COPY(); + RAPIDJSON_COPY(); if (!(c & 0x80)) return true; bool result = true; switch (GetRange(static_cast(c))) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + case 2: RAPIDJSON_TAIL(); return result; + case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; + case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; + case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; + case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; default: return false; } -#undef COPY -#undef TRANS -#undef TAIL +#undef RAPIDJSON_COPY +#undef RAPIDJSON_TRANS +#undef RAPIDJSON_TAIL } static unsigned char GetRange(unsigned char c) { @@ -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/src/lottie/rapidjson/filereadstream.h b/src/lottie/rapidjson/filereadstream.h index f1bfb7d..6b34370 100644 --- a/src/lottie/rapidjson/filereadstream.h +++ b/src/lottie/rapidjson/filereadstream.h @@ -59,7 +59,7 @@ public: // For encoding detection only. const Ch* Peek4() const { - return (current_ + 4 <= bufferLast_) ? current_ : 0; + return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; } private: diff --git a/src/lottie/rapidjson/filewritestream.h b/src/lottie/rapidjson/filewritestream.h index 3811f8b..8b48fee 100644 --- a/src/lottie/rapidjson/filewritestream.h +++ b/src/lottie/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 */ diff --git a/src/lottie/rapidjson/internal/biginteger.h b/src/lottie/rapidjson/internal/biginteger.h index 9d3e88c..a31c8a8 100644 --- a/src/lottie/rapidjson/internal/biginteger.h +++ b/src/lottie/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 @@ -133,7 +133,7 @@ public: RAPIDJSON_ASSERT(count_ + offset <= kCapacity); if (interShift == 0) { - std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); + std::memmove(digits_ + offset, digits_, count_ * sizeof(Type)); count_ += offset; } else { diff --git a/src/lottie/rapidjson/internal/diyfp.h b/src/lottie/rapidjson/internal/diyfp.h index 29abf80..b6c2cf5 100644 --- a/src/lottie/rapidjson/internal/diyfp.h +++ b/src/lottie/rapidjson/internal/diyfp.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. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: @@ -20,6 +20,7 @@ #define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" +#include #if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include @@ -56,7 +57,7 @@ struct DiyFp { if (biased_e != 0) { f = significand + kDpHiddenBit; e = biased_e - kDpExponentBias; - } + } else { f = significand; e = kDpMinExponent + 1; @@ -99,6 +100,7 @@ struct DiyFp { } DiyFp Normalize() const { + RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737 #if defined(_MSC_VER) && defined(_M_AMD64) unsigned long index; _BitScanReverse64(&index, f); @@ -141,7 +143,16 @@ struct DiyFp { double d; uint64_t u64; }u; - const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask); + if (e < kDpDenormalExponent) { + // Underflow. + return 0.0; + } + if (e >= kDpMaxExponent) { + // Overflow. + return std::numeric_limits::infinity(); + } + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : static_cast(e + kDpExponentBias); u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); return u.d; @@ -220,9 +231,10 @@ inline DiyFp GetCachedPowerByIndex(size_t index) { 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 }; + RAPIDJSON_ASSERT(index < 87); return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); } - + inline DiyFp GetCachedPower(int e, int* K) { //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; @@ -238,10 +250,11 @@ inline DiyFp GetCachedPower(int e, int* K) { } inline DiyFp GetCachedPower10(int exp, int *outExp) { - unsigned index = (static_cast(exp) + 348u) / 8u; - *outExp = -348 + static_cast(index) * 8; - return GetCachedPowerByIndex(index); - } + RAPIDJSON_ASSERT(exp >= -348); + unsigned index = static_cast(exp + 348) / 8u; + *outExp = -348 + static_cast(index) * 8; + return GetCachedPowerByIndex(index); +} #ifdef __GNUC__ RAPIDJSON_DIAG_POP diff --git a/src/lottie/rapidjson/internal/ieee754.h b/src/lottie/rapidjson/internal/ieee754.h index 56b2bb1..c2684ba 100644 --- a/src/lottie/rapidjson/internal/ieee754.h +++ b/src/lottie/rapidjson/internal/ieee754.h @@ -22,7 +22,7 @@ namespace internal { class Double { public: - Double() = default; + Double() {} Double(double d) : d_(d) {} Double(uint64_t u) : u_(u) {} diff --git a/src/lottie/rapidjson/internal/itoa.h b/src/lottie/rapidjson/internal/itoa.h index 01a4e7e..9b1c45c 100644 --- a/src/lottie/rapidjson/internal/itoa.h +++ b/src/lottie/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; @@ -207,9 +211,8 @@ inline char* u64toa(uint64_t value, char* buffer) { *buffer++ = cDigitsLut[d3 + 1]; if (value >= kTen9) *buffer++ = cDigitsLut[d4]; - if (value >= kTen8) - *buffer++ = cDigitsLut[d4 + 1]; - + + *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; @@ -222,7 +225,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 +235,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 +248,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 +287,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++ = '-'; diff --git a/src/lottie/rapidjson/internal/meta.h b/src/lottie/rapidjson/internal/meta.h index 5a9aaa4..d401edf 100644 --- a/src/lottie/rapidjson/internal/meta.h +++ b/src/lottie/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/src/lottie/rapidjson/internal/regex.h b/src/lottie/rapidjson/internal/regex.h index e1a2faa..16e3559 100644 --- a/src/lottie/rapidjson/internal/regex.h +++ b/src/lottie/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 @@ -120,7 +118,8 @@ public: template friend class GenericRegexSearch; GenericRegex(const Ch* source, Allocator* allocator = 0) : - states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), + ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_), + states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), anchorBegin_(), anchorEnd_() { GenericStringStream ss(source); @@ -128,7 +127,10 @@ public: Parse(ds); } - ~GenericRegex() {} + ~GenericRegex() + { + RAPIDJSON_DELETE(ownAllocator_); + } bool IsValid() const { return root_ != kRegexInvalidState; @@ -190,10 +192,9 @@ private: template void Parse(DecodedStream& ds) { - Allocator allocator; - Stack operandStack(&allocator, 256); // Frag - Stack operatorStack(&allocator, 256); // Operator - Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) + Stack operandStack(allocator_, 256); // Frag + Stack operatorStack(allocator_, 256); // Operator + Stack atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis) *atomCountStack.template Push() = 0; @@ -394,8 +395,7 @@ private: } return false; - default: - RAPIDJSON_ASSERT(op == kOneOrMore); + case kOneOrMore: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); @@ -404,6 +404,10 @@ private: return true; } return false; + + default: + // syntax error (e.g. unclosed kLeftParenthesis) + return false; } } @@ -584,6 +588,8 @@ private: } } + Allocator* ownAllocator_; + Allocator* allocator_; Stack states_; Stack ranges_; SizeType root_; @@ -723,11 +729,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/src/lottie/rapidjson/internal/stack.h b/src/lottie/rapidjson/internal/stack.h index 5c5398c..45dca6a 100644 --- a/src/lottie/rapidjson/internal/stack.h +++ b/src/lottie/rapidjson/internal/stack.h @@ -17,6 +17,7 @@ #include "../allocators.h" #include "swap.h" +#include #if defined(__clang__) RAPIDJSON_DIAG_PUSH @@ -100,7 +101,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; @@ -114,7 +115,7 @@ public: template RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed - if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) + if (RAPIDJSON_UNLIKELY(static_cast(sizeof(T) * count) > (stackEnd_ - stackTop_))) Expand(count); } @@ -127,7 +128,7 @@ public: template RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { RAPIDJSON_ASSERT(stackTop_); - RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); + RAPIDJSON_ASSERT(static_cast(sizeof(T) * count) <= (stackEnd_ - stackTop_)); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; return ret; diff --git a/src/lottie/rapidjson/internal/strtod.h b/src/lottie/rapidjson/internal/strtod.h index adf49e3..dfca22b 100644 --- a/src/lottie/rapidjson/internal/strtod.h +++ b/src/lottie/rapidjson/internal/strtod.h @@ -19,6 +19,8 @@ #include "biginteger.h" #include "diyfp.h" #include "pow10.h" +#include +#include RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -126,20 +128,20 @@ inline bool StrtodFast(double d, int p, double* result) { } // Compute an approximation and see if it is within 1/2 ULP -inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { +inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) { uint64_t significand = 0; - size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 - for (; i < length; i++) { + int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 + for (; i < dLen; i++) { if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) break; significand = significand * 10u + static_cast(decimals[i] - '0'); } - if (i < length && decimals[i] >= '5') // Rounding + if (i < dLen && decimals[i] >= '5') // Rounding significand++; - size_t remaining = length - i; + int remaining = dLen - i; const int kUlpShift = 3; const int kUlp = 1 << kUlpShift; int64_t error = (remaining == 0) ? 0 : kUlp / 2; @@ -148,24 +150,24 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit v = v.Normalize(); error <<= -v.e; - const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; + dExp += remaining; int actualExp; DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); if (actualExp != dExp) { static const DiyFp kPow10[] = { - DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 - DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 - DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 - DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 - DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 - DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 - DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 + DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1 + DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2 + DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3 + DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4 + DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5 + DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6 + DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7 }; - int adjustment = dExp - actualExp - 1; - RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); - v = v * kPow10[adjustment]; - if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit + int adjustment = dExp - actualExp; + RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8); + v = v * kPow10[adjustment - 1]; + if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit error += kUlp / 2; } @@ -203,9 +205,9 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); } -inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { - const BigInteger dInt(decimals, length); - const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; +inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) { + RAPIDJSON_ASSERT(dLen >= 0); + const BigInteger dInt(decimals, static_cast(dLen)); Double a(approx); int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); if (cmp < 0) @@ -225,42 +227,61 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t RAPIDJSON_ASSERT(d >= 0.0); RAPIDJSON_ASSERT(length >= 1); - double result; + double result = 0.0; if (StrtodFast(d, p, &result)) return result; + RAPIDJSON_ASSERT(length <= INT_MAX); + int dLen = static_cast(length); + + RAPIDJSON_ASSERT(length >= decimalPosition); + RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX); + int dExpAdjust = static_cast(length - decimalPosition); + + RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust); + int dExp = exp - dExpAdjust; + + // Make sure length+dExp does not overflow + RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen); + // Trim leading zeros - while (*decimals == '0' && length > 1) { - length--; + while (dLen > 0 && *decimals == '0') { + dLen--; decimals++; - decimalPosition--; } // Trim trailing zeros - while (decimals[length - 1] == '0' && length > 1) { - length--; - decimalPosition--; - exp++; + while (dLen > 0 && decimals[dLen - 1] == '0') { + dLen--; + dExp++; + } + + if (dLen == 0) { // Buffer only contains zeros. + return 0.0; } // Trim right-most digits - const int kMaxDecimalDigit = 780; - if (static_cast(length) > kMaxDecimalDigit) { - int delta = (static_cast(length) - kMaxDecimalDigit); - exp += delta; - decimalPosition -= static_cast(delta); - length = kMaxDecimalDigit; + const int kMaxDecimalDigit = 767 + 1; + if (dLen > kMaxDecimalDigit) { + dExp += dLen - kMaxDecimalDigit; + dLen = kMaxDecimalDigit; } - // If too small, underflow to zero - if (int(length) + exp < -324) + // If too small, underflow to zero. + // Any x <= 10^-324 is interpreted as zero. + if (dLen + dExp <= -324) return 0.0; - if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) + // If too large, overflow to infinity. + // Any x >= 10^309 is interpreted as +infinity. + if (dLen + dExp > 309) + return std::numeric_limits::infinity(); + + if (StrtodDiyFp(decimals, dLen, dExp, &result)) return result; // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison - return StrtodBigInteger(result, decimals, length, decimalPosition, exp); + return StrtodBigInteger(result, decimals, dLen, dExp); } } // namespace internal diff --git a/src/lottie/rapidjson/istreamwrapper.h b/src/lottie/rapidjson/istreamwrapper.h index 8639c8c..c4950b9 100644 --- a/src/lottie/rapidjson/istreamwrapper.h +++ b/src/lottie/rapidjson/istreamwrapper.h @@ -17,13 +17,12 @@ #include "stream.h" #include +#include #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 @@ -50,57 +49,71 @@ template class BasicIStreamWrapper { public: typedef typename StreamType::char_type Ch; - BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} - Ch Peek() const { - typename StreamType::int_type c = stream_.peek(); - return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : static_cast('\0'); + //! Constructor. + /*! + \param stream stream opened for read. + */ + BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + Read(); } - Ch Take() { - typename StreamType::int_type c = stream_.get(); - if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { - count_++; - return static_cast(c); - } - else - return '\0'; + //! Constructor. + /*! + \param stream stream opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); } - // tellg() may return -1 when failed. So we count by ourself. - size_t Tell() const { return count_; } + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { - RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. - int i; - bool hasError = false; - for (i = 0; i < 4; ++i) { - typename StreamType::int_type c = stream_.get(); - if (c == StreamType::traits_type::eof()) { - hasError = true; - stream_.clear(); - break; - } - peekBuffer_[i] = static_cast(c); - } - for (--i; i >= 0; --i) - stream_.putback(peekBuffer_[i]); - return !hasError ? peekBuffer_ : 0; + return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0; } private: + BasicIStreamWrapper(); BasicIStreamWrapper(const BasicIStreamWrapper&); BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); - StreamType& stream_; - size_t count_; //!< Number of characters read. Note: - mutable Ch peekBuffer_[4]; + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = bufferSize_; + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; + + if (!stream_.read(buffer_, static_cast(bufferSize_))) { + readCount_ = static_cast(stream_.gcount()); + *(bufferLast_ = buffer_ + readCount_) = '\0'; + eof_ = true; + } + } + } + + StreamType &stream_; + Ch peekBuffer_[4], *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; }; typedef BasicIStreamWrapper IStreamWrapper; diff --git a/src/lottie/rapidjson/meson.build b/src/lottie/rapidjson/meson.build deleted file mode 100644 index 2809bab..0000000 --- a/src/lottie/rapidjson/meson.build +++ /dev/null @@ -1,8 +0,0 @@ -ssg_sources_lottie_rapidjson = [] - -ssg_lottie_rapidjson_file = ['jsontest.cpp' - ] - -foreach file: ssg_lottie_rapidjson_file - ssg_sources_lottie_rapidjson += join_paths('rapidjson', file) -endforeach diff --git a/src/lottie/rapidjson/pointer.h b/src/lottie/rapidjson/pointer.h index 0f377ef..063abab 100644 --- a/src/lottie/rapidjson/pointer.h +++ b/src/lottie/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 @@ -165,7 +163,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; } @@ -197,6 +200,36 @@ public: return *this; } + //! Swap the content of this pointer with an other. + /*! + \param other The pointer to swap with. + \note Constant complexity. + */ + GenericPointer& Swap(GenericPointer& other) RAPIDJSON_NOEXCEPT { + internal::Swap(allocator_, other.allocator_); + internal::Swap(ownAllocator_, other.ownAllocator_); + internal::Swap(nameBuffer_, other.nameBuffer_); + internal::Swap(tokens_, other.tokens_); + internal::Swap(tokenCount_, other.tokenCount_); + internal::Swap(parseErrorOffset_, other.parseErrorOffset_); + internal::Swap(parseErrorCode_, other.parseErrorCode_); + return *this; + } + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.pointer, b.pointer); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericPointer& a, GenericPointer& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + //@} //!@name Append token @@ -353,6 +386,33 @@ public: */ bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } + //! Less than operator. + /*! + \note Invalid pointers are always greater than valid ones. + */ + bool operator<(const GenericPointer& rhs) const { + if (!IsValid()) + return false; + if (!rhs.IsValid()) + return true; + + if (tokenCount_ != rhs.tokenCount_) + return tokenCount_ < rhs.tokenCount_; + + for (size_t i = 0; i < tokenCount_; i++) { + if (tokens_[i].index != rhs.tokens_[i].index) + return tokens_[i].index < rhs.tokens_[i].index; + + if (tokens_[i].length != rhs.tokens_[i].length) + return tokens_[i].length < rhs.tokens_[i].length; + + if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length)) + return cmp < 0; + } + + return false; + } + //@} //!@name Stringify @@ -532,14 +592,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); } @@ -547,7 +607,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 @@ -1347,11 +1407,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/src/lottie/rapidjson/prettywriter.h b/src/lottie/rapidjson/prettywriter.h index 98dfb30..45afb69 100644 --- a/src/lottie/rapidjson/prettywriter.h +++ b/src/lottie/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. @@ -92,26 +92,26 @@ public: */ //@{ - bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } - bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } - bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } - bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } - bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } - bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } - bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } + bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); } + bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); } + bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); } + bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); } + bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); } + bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); } + bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); } bool RawNumber(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kNumberType); - return Base::WriteString(str, length); + return Base::EndValue(Base::WriteString(str, length)); } bool String(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kStringType); - return Base::WriteString(str, length); + return Base::EndValue(Base::WriteString(str, length)); } #if RAPIDJSON_HAS_STDSTRING @@ -146,7 +146,7 @@ public: Base::os_->Put('\n'); WriteIndent(); } - bool ret = Base::WriteEndObject(); + bool ret = Base::EndValue(Base::WriteEndObject()); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text @@ -170,7 +170,7 @@ public: Base::os_->Put('\n'); WriteIndent(); } - bool ret = Base::WriteEndArray(); + bool ret = Base::EndValue(Base::WriteEndArray()); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text @@ -201,7 +201,7 @@ public: bool RawValue(const Ch* json, size_t length, Type type) { RAPIDJSON_ASSERT(json != 0); PrettyPrefix(type); - return Base::WriteRawValue(json, length); + return Base::EndValue(Base::WriteRawValue(json, length)); } protected: diff --git a/src/lottie/rapidjson/rapidjson.h b/src/lottie/rapidjson/rapidjson.h index 256b0d5..549936f 100644 --- a/src/lottie/rapidjson/rapidjson.h +++ b/src/lottie/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 @@ -269,16 +269,11 @@ /*! \ingroup RAPIDJSON_CONFIG \param x pointer to align - Some machines require strict data alignment. Currently the default uses 4 bytes - alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms. + Some machines require strict data alignment. The default is 8 bytes. User can customize by defining the RAPIDJSON_ALIGN function macro. */ #ifndef RAPIDJSON_ALIGN -#if RAPIDJSON_64BIT == 1 -#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) -#else -#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) -#endif +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) #endif /////////////////////////////////////////////////////////////////////////////// @@ -433,7 +428,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 @@ -539,19 +534,18 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // C++11 features -//enable c++11 feature -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #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 #endif #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1600) + (defined(_MSC_VER) && _MSC_VER >= 1600) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else @@ -562,8 +556,9 @@ RAPIDJSON_NAMESPACE_END #ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) -// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1900) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) #define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 #else #define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 @@ -577,14 +572,19 @@ RAPIDJSON_NAMESPACE_END // no automatic detection, yet #ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS +#if (defined(_MSC_VER) && _MSC_VER >= 1700) +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 1 +#else #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 #endif +#endif #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ - (defined(_MSC_VER) && _MSC_VER >= 1700) + (defined(_MSC_VER) && _MSC_VER >= 1700) || \ + (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) #define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 #else #define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 @@ -593,6 +593,32 @@ RAPIDJSON_NAMESPACE_END //!@endcond +//! Assertion (in non-throwing contexts). + /*! \ingroup RAPIDJSON_CONFIG + Some functions provide a \c noexcept guarantee, if the compiler supports it. + In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to + throw an exception. This macro adds a separate customization point for + such cases. + + Defaults to C \c assert() (as \ref RAPIDJSON_ASSERT), if \c noexcept is + supported, and to \ref RAPIDJSON_ASSERT otherwise. + */ + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_NOEXCEPT_ASSERT + +#ifndef RAPIDJSON_NOEXCEPT_ASSERT +#ifdef RAPIDJSON_ASSERT_THROWS +#if RAPIDJSON_HAS_CXX11_NOEXCEPT +#define RAPIDJSON_NOEXCEPT_ASSERT(x) +#else +#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT +#else +#define RAPIDJSON_NOEXCEPT_ASSERT(x) RAPIDJSON_ASSERT(x) +#endif // RAPIDJSON_ASSERT_THROWS +#endif // RAPIDJSON_NOEXCEPT_ASSERT + /////////////////////////////////////////////////////////////////////////////// // new/delete diff --git a/src/lottie/rapidjson/reader.h b/src/lottie/rapidjson/reader.h index 2056e21..44a6bcd 100644 --- a/src/lottie/rapidjson/reader.h +++ b/src/lottie/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__ @@ -544,7 +542,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. @@ -607,7 +606,7 @@ public: parseResult_.Clear(); state_ = IterativeParsingStartState; } - + //! Parse one token from JSON text /*! \tparam InputStream Type of input stream, implementing Stream concept \tparam Handler Type of handler, implementing Handler concept. @@ -619,11 +618,11 @@ public: bool IterativeParseNext(InputStream& is, Handler& handler) { while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { SkipWhitespaceAndComments(is); - + Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state_, t); IterativeParsingState d = Transit(state_, t, n, is, handler); - + // If we've finished or hit an error... if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { // Report errors. @@ -631,11 +630,11 @@ public: HandleError(state_, is); return false; } - + // Transition to the finish state. RAPIDJSON_ASSERT(d == IterativeParsingFinishState); state_ = d; - + // If StopWhenDone is not set... if (!(parseFlags & kParseStopWhenDoneFlag)) { // ... and extra non-whitespace data is found... @@ -646,11 +645,11 @@ public: return false; } } - + // Success! We are done! return true; } - + // Transition to the new state. state_ = d; @@ -658,7 +657,7 @@ public: if (!IsIterativeParsingDelimiterState(n)) return true; } - + // We reached the end of file. stack_.Clear(); @@ -666,18 +665,18 @@ public: HandleError(state_, is); return false; } - + return true; } - + //! 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_); } - //! 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. @@ -900,7 +899,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; @@ -1007,7 +1006,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)])) { @@ -1524,7 +1523,7 @@ private: } } } - + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); } @@ -1562,8 +1561,6 @@ private: // Force double for big integer if (useDouble) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { - if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); d = d * 10 + (s.TakePush() - '0'); } } @@ -1633,9 +1630,18 @@ private: if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = static_cast(s.Take() - '0'); if (expMinus) { + // (exp + expFrac) must not underflow int => we're detecting when -exp gets + // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into + // underflow territory): + // + // -(exp * 10 + 9) + expFrac >= INT_MIN + // <=> exp <= (expFrac - INT_MIN - 9) / 10 + RAPIDJSON_ASSERT(expFrac <= 0); + int maxExp = (expFrac + 2147483639) / 10; + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast(s.Take() - '0'); - if (exp >= 214748364) { // Issue #313: prevent overflow exponent + if (RAPIDJSON_UNLIKELY(exp > maxExp)) { while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent s.Take(); } @@ -1694,6 +1700,13 @@ private: else d = internal::StrtodNormalPrecision(d, p); + // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal + if (d > (std::numeric_limits::max)()) { + // Overflow + // TODO: internal::StrtodX should report overflow (or underflow) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); + } + cont = handler.Double(minus ? -d : d); } else if (useNanOrInf) { @@ -1756,12 +1769,12 @@ private: // Single value state IterativeParsingValueState, - + // Delimiter states (at bottom) IterativeParsingElementDelimiterState, IterativeParsingMemberDelimiterState, IterativeParsingKeyValueDelimiterState, - + cIterativeParsingStateCount }; @@ -1785,7 +1798,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 +1825,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,53 +2164,53 @@ 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; } - + template ParseResult IterativeParse(InputStream& is, Handler& handler) { parseResult_.Clear(); ClearStackOnExit scope(*this); IterativeParsingState state = IterativeParsingStartState; - + SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); IterativeParsingState d = Transit(state, t, n, is, handler); - + if (d == IterativeParsingErrorState) { HandleError(state, is); break; } - + state = d; - + // Do not further consume streams if a root JSON has been parsed. if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) break; - + SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } - + // Handle the end of file. if (state != IterativeParsingFinishState) HandleError(state, is); - + return parseResult_; } static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. ParseResult parseResult_; - IterativeParsingState state_{IterativeParsingStartState}; + IterativeParsingState state_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. @@ -2205,7 +2218,7 @@ typedef GenericReader, UTF8<> > Reader; RAPIDJSON_NAMESPACE_END -#ifdef __clang__ +#if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif @@ -2214,8 +2227,4 @@ RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP #endif -#ifdef _MSC_VER -RAPIDJSON_DIAG_POP -#endif - #endif // RAPIDJSON_READER_H_ diff --git a/src/lottie/rapidjson/schema.h b/src/lottie/rapidjson/schema.h index 2713fb2..26ae947 100644 --- a/src/lottie/rapidjson/schema.h +++ b/src/lottie/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) @@ -25,7 +26,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 @@ -62,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 @@ -157,6 +156,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 @@ -261,6 +316,7 @@ template struct SchemaValidationContext { typedef Schema SchemaType; typedef ISchemaStateFactory SchemaValidatorFactoryType; + typedef IValidationErrorHandler ErrorHandlerType; typedef typename SchemaType::ValueType ValueType; typedef typename ValueType::Ch Ch; @@ -270,8 +326,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(), @@ -311,6 +368,7 @@ struct SchemaValidationContext { } SchemaValidatorFactoryType& factory; + ErrorHandlerType& error_handler; const SchemaType* schema; const SchemaType* valueSchema; const Ch* invalidKeyword; @@ -345,10 +403,13 @@ 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) : allocator_(allocator), + uri_(schemaDocument->GetURI(), *allocator), + pointer_(p, allocator), typeless_(schemaDocument->GetTypeless()), enum_(), enumCount_(), @@ -379,7 +440,8 @@ public: minLength_(0), maxLength_(~SizeType(0)), exclusiveMinimum_(false), - exclusiveMaximum_(false) + exclusiveMaximum_(false), + defaultValueLength_(0) { typedef typename SchemaDocumentType::ValueType ValueType; typedef typename ValueType::ConstValueIterator ConstValueIterator; @@ -402,7 +464,7 @@ public: enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { typedef Hasher > EnumHasherType; - char buffer[256 + 24]; + char buffer[256u + 24]; MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); EnumHasherType h(&hasherAllocator, 256); itr->Accept(h); @@ -574,6 +636,12 @@ public: if (const ValueType* v = GetMember(value, GetMultipleOfString())) if (v->IsNumber() && v->GetDouble() > 0.0) multipleOf_.CopyFrom(*v, *allocator_); + + // Default + if (const ValueType* v = GetMember(value, GetDefaultValueString())) + if (v->IsString()) + defaultValueLength_ = v->GetStringLength(); + } ~Schema() { @@ -597,6 +665,14 @@ public: #endif } + const SValue& GetURI() const { + return uri_; + } + + const PointerType& GetPointer() const { + return pointer_; + } + bool BeginValue(Context& context) const { if (context.inArray) { if (uniqueItems_) @@ -611,8 +687,10 @@ public: context.valueSchema = additionalItemsSchema_; else if (additionalItems_) context.valueSchema = typeless_; - else + else { + context.error_handler.DisallowedItem(context.arrayElementIndex); RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); + } } else context.valueSchema = typeless_; @@ -637,15 +715,21 @@ public: } if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { - if (!patternValid) + if (!patternValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } } else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { - if (!patternValid || !otherValid) + if (!patternValid || !otherValid) { + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } } - else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) + else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty) + context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } } if (enum_) { @@ -653,19 +737,23 @@ public: for (SizeType i = 0; i < enumCount_; i++) if (enum_[i] == h) goto foundEnum; + context.error_handler.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()) { + context.error_handler.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; + context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); foundAny:; } @@ -674,30 +762,39 @@ public: bool oneValid = false; for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) if (context.validators[i]->IsValid()) { - if (oneValid) + if (oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); - else + } else oneValid = true; } - if (!oneValid) + if (!oneValid) { + context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count); RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } } - if (not_ && context.validators[notValidatorIndex_]->IsValid()) + if (not_ && context.validators[notValidatorIndex_]->IsValid()) { + context.error_handler.Disallowed(); RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); + } return true; } - bool Null(Context& context) const { - if (!(type_ & (1 << kNullSchemaType))) + bool Null(Context& context) const { + if (!(type_ & (1 << kNullSchemaType))) { + DisallowedType(context, GetNullString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } return CreateParallelValidator(context); } - bool Bool(Context& context, bool) const { - if (!(type_ & (1 << kBooleanSchemaType))) + bool Bool(Context& context, bool) const { + if (!(type_ & (1 << kBooleanSchemaType))) { + DisallowedType(context, GetBooleanString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } return CreateParallelValidator(context); } @@ -726,8 +823,10 @@ public: } bool Double(Context& context, double d) const { - if (!(type_ & (1 << kNumberSchemaType))) + if (!(type_ & (1 << kNumberSchemaType))) { + DisallowedType(context, GetNumberString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) return false; @@ -742,28 +841,38 @@ public: } bool String(Context& context, const Ch* str, SizeType length, bool) const { - if (!(type_ & (1 << kStringSchemaType))) + if (!(type_ & (1 << kStringSchemaType))) { + DisallowedType(context, 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_) { + context.error_handler.TooShort(str, length, minLength_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); - if (count > maxLength_) + } + if (count > maxLength_) { + context.error_handler.TooLong(str, length, maxLength_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); + } } } - if (pattern_ && !IsPatternMatch(pattern_, str, length)) + if (pattern_ && !IsPatternMatch(pattern_, str, length)) { + context.error_handler.DoesNotMatch(str, length); RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); + } return CreateParallelValidator(context); } - bool StartObject(Context& context) const { - if (!(type_ & (1 << kObjectSchemaType))) + bool StartObject(Context& context) const { + if (!(type_ & (1 << kObjectSchemaType))) { + DisallowedType(context, GetObjectString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } if (hasDependencies_ || hasRequired_) { context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); @@ -821,45 +930,66 @@ public: return true; } - if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties + if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties + context.error_handler.DisallowedProperty(str, len); RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); + } return true; } bool EndObject(Context& context, SizeType memberCount) const { - if (hasRequired_) + if (hasRequired_) { + context.error_handler.StartMissingProperties(); for (SizeType index = 0; index < propertyCount_; index++) - if (properties_[index].required) - if (!context.propertyExist[index]) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + if (properties_[index].required && !context.propertyExist[index]) + if (properties_[index].schema->defaultValueLength_ == 0 ) + context.error_handler.AddMissingProperty(properties_[index].name); + if (context.error_handler.EndMissingProperties()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + } - if (memberCount < minProperties_) + if (memberCount < minProperties_) { + context.error_handler.TooFewProperties(memberCount, minProperties_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); + } - if (memberCount > maxProperties_) + if (memberCount > maxProperties_) { + context.error_handler.TooManyProperties(memberCount, maxProperties_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); + } if (hasDependencies_) { - for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) + context.error_handler.StartDependencyErrors(); + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) { + const Property& source = properties_[sourceIndex]; if (context.propertyExist[sourceIndex]) { - if (properties_[sourceIndex].dependencies) { + if (source.dependencies) { + context.error_handler.StartMissingDependentProperties(); for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) - if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex]) + 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()) + context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator); } - else if (properties_[sourceIndex].dependenciesSchema) - if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) - RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); } + } + if (context.error_handler.EndDependencyErrors()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); } return true; } - bool StartArray(Context& context) const { - if (!(type_ & (1 << kArraySchemaType))) + bool StartArray(Context& context) const { + if (!(type_ & (1 << kArraySchemaType))) { + DisallowedType(context, GetArrayString()); RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + } context.arrayElementIndex = 0; context.inArray = true; @@ -867,14 +997,18 @@ public: return CreateParallelValidator(context); } - bool EndArray(Context& context, SizeType elementCount) const { + bool EndArray(Context& context, SizeType elementCount) const { context.inArray = false; - if (elementCount < minItems_) + if (elementCount < minItems_) { + context.error_handler.TooFewItems(elementCount, minItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); + } - if (elementCount > maxItems_) + if (elementCount > maxItems_) { + context.error_handler.TooManyItems(elementCount, maxItems_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); + } return true; } @@ -920,6 +1054,7 @@ public: RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') + RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't') #undef RAPIDJSON_STRING_ @@ -1014,12 +1149,15 @@ private: #elif RAPIDJSON_SCHEMA_USE_STDREGEX template RegexType* CreatePattern(const ValueType& value) { - if (value.IsString()) + if (value.IsString()) { + RegexType *r = static_cast(allocator_->Malloc(sizeof(RegexType))); try { - return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); + return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); } catch (const std::regex_error&) { + AllocatorType::Free(r); } + } return 0; } @@ -1095,15 +1233,20 @@ private: } bool CheckInt(Context& context, int64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, 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()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } } else if (minimum_.IsUint64()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() } else if (!CheckDoubleMinimum(context, static_cast(i))) @@ -1112,8 +1255,10 @@ private: if (!maximum_.IsNull()) { if (maximum_.IsInt64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } } else if (maximum_.IsUint64()) { } /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() @@ -1123,8 +1268,10 @@ private: 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) { + context.error_handler.NotMultipleOf(i, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } } else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; @@ -1134,13 +1281,17 @@ private: } bool CheckUint(Context& context, uint64_t i) const { - if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) { + DisallowedType(context, 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()) { + context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } } else if (minimum_.IsInt64()) /* do nothing */; // i >= 0 > minimum.Getint64() @@ -1150,19 +1301,25 @@ private: if (!maximum_.IsNull()) { if (maximum_.IsUint64()) { - if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } } - else if (maximum_.IsInt64()) + else if (maximum_.IsInt64()) { + context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ + } else if (!CheckDoubleMaximum(context, static_cast(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { - if (i % multipleOf_.GetUint64() != 0) + if (i % multipleOf_.GetUint64() != 0) { + context.error_handler.NotMultipleOf(i, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } } else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; @@ -1172,14 +1329,18 @@ private: } bool CheckDoubleMinimum(Context& context, double d) const { - if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) { + context.error_handler.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()) + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) { + context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } return true; } @@ -1187,11 +1348,29 @@ private: 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) { + context.error_handler.NotMultipleOf(d, multipleOf_); RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } return true; } + void DisallowedType(Context& context, const ValueType& actualType) const { + ErrorHandler& eh = context.error_handler; + 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); } @@ -1216,6 +1395,8 @@ private: }; AllocatorType* allocator_; + SValue uri_; + PointerType pointer_; const SchemaType* typeless_; uint64_t* enum_; SizeType enumCount_; @@ -1257,6 +1438,8 @@ private: SValue multipleOf_; bool exclusiveMinimum_; bool exclusiveMaximum_; + + SizeType defaultValueLength_; }; template @@ -1325,6 +1508,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; @@ -1334,10 +1518,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_(), @@ -1349,8 +1536,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. @@ -1388,7 +1578,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; @@ -1410,6 +1601,8 @@ public: RAPIDJSON_DELETE(ownAllocator_); } + const URIType& GetURI() const { return uri_; } + //! Get the root schema. const SchemaType& GetRoot() const { return *root_; } @@ -1492,6 +1685,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; } } @@ -1540,6 +1734,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. @@ -1568,13 +1763,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. /*! @@ -1596,6 +1795,9 @@ public: schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(0), + error_(kObjectType), + currentError_(), + missingDependents_(), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) @@ -1624,6 +1826,9 @@ public: schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(&outputHandler), + error_(kObjectType), + currentError_(), + missingDependents_(), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) @@ -1642,6 +1847,9 @@ public: while (!schemaStack_.Empty()) PopSchema(); documentStack_.Clear(); + error_.SetObject(); + currentError_.SetNull(); + missingDependents_.SetNull(); valid_ = true; } @@ -1649,9 +1857,13 @@ 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() : schemaDocument_->GetPointer(&CurrentSchema()); + return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer(); } //! Gets the keyword of invalid schema. @@ -1661,9 +1873,196 @@ 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) { + 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) { + for (SizeType i = 0; i < count; ++i) { + MergeError(static_cast(subvalidators[i])->GetError()); + } + } + 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\ @@ -1702,7 +2101,7 @@ RAPIDJSON_MULTILINEMACRO_END RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) - bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } + 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)); } @@ -1755,7 +2154,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 @@ -1798,6 +2197,7 @@ private: GenericSchemaValidator( const SchemaDocumentType& schemaDocument, const SchemaType& root, + const char* basePath, size_t basePathSize, #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth, #endif @@ -1812,11 +2212,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() { @@ -1880,8 +2285,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()); } } @@ -1910,7 +2317,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); @@ -1921,6 +2328,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(); } @@ -1934,6 +2405,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_; @@ -1965,13 +2439,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) { @@ -1984,11 +2459,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_; @@ -1999,6 +2476,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_; @@ -2008,6 +2486,8 @@ private: PointerType invalidSchemaPointer_; const Ch* invalidSchemaKeyword_; PointerType invalidDocumentPointer_; + StackAllocator allocator_; + ValueType error_; bool isValid_; }; diff --git a/src/lottie/rapidjson/writer.h b/src/lottie/rapidjson/writer.h index e610ebb..6f5b690 100644 --- a/src/lottie/rapidjson/writer.h +++ b/src/lottie/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 @@ -460,9 +458,13 @@ 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)) { + RAPIDJSON_ASSERT(is.Peek() != '\0'); + if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; } return true; } @@ -700,11 +702,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