#pragma once #include "CesiumUtility/Assert.h" #include "DoubleJsonHandler.h" #include "IntegerJsonHandler.h" #include "JsonHandler.h" #include "Library.h" #include "StringJsonHandler.h" #include #include #include namespace CesiumJsonReader { /** * @brief \ref IJsonHandler for reading a JSON array into an `std::vector`. * * @tparam T The element type of the destination vector. * @tparam THandler The \ref IJsonHandler to handle each element. */ template class CESIUMJSONREADER_API ArrayJsonHandler : public JsonHandler { public: /** @brief The destination type. */ using ValueType = std::vector; /** * @brief Creates a new \ref ArrayJsonHandler. * * @param args The arguments that will be passed to the constructor of * THandler when it's instantiated. */ template ArrayJsonHandler(Ts&&... args) noexcept : JsonHandler(), _handlerFactory( std::bind(handlerFactory, std::forward(args)...)), _objectHandler() {} /** * @brief Resets the parent and destination array of this \ref * ArrayJsonHandler. */ void reset(IJsonHandler* pParent, std::vector* pArray) { JsonHandler::reset(pParent); this->_pArray = pArray; this->_arrayIsOpen = false; this->_objectHandler.reset(this->_handlerFactory()); } virtual IJsonHandler* readNull() override { return this->invalid("A null")->readNull(); } virtual IJsonHandler* readBool(bool b) override { return this->invalid("A boolean")->readBool(b); } virtual IJsonHandler* readInt32(int32_t i) override { return this->invalid("An integer")->readInt32(i); } virtual IJsonHandler* readUint32(uint32_t i) override { return this->invalid("An integer")->readUint32(i); } virtual IJsonHandler* readInt64(int64_t i) override { return this->invalid("An integer")->readInt64(i); } virtual IJsonHandler* readUint64(uint64_t i) override { return this->invalid("An integer")->readUint64(i); } virtual IJsonHandler* readDouble(double d) override { return this->invalid("A double (floating-point)")->readDouble(d); } virtual IJsonHandler* readString(const std::string_view& str) override { return this->invalid("A string")->readString(str); } virtual IJsonHandler* readObjectStart() override { if (!this->_arrayIsOpen) { return this->invalid("An object")->readObjectStart(); } CESIUM_ASSERT(this->_pArray); T& o = this->_pArray->emplace_back(); this->_objectHandler->reset(this, &o); return this->_objectHandler->readObjectStart(); } virtual IJsonHandler* readObjectKey(const std::string_view& /*str*/) noexcept override { return nullptr; } virtual IJsonHandler* readObjectEnd() noexcept override { return nullptr; } virtual IJsonHandler* readArrayStart() override { if (this->_arrayIsOpen) { return this->invalid("An array")->readArrayStart(); } this->_arrayIsOpen = true; this->_pArray->clear(); return this; } virtual IJsonHandler* readArrayEnd() override { return this->parent(); } virtual void reportWarning( const std::string& warning, std::vector&& context = std::vector()) override { context.push_back( std::string("[") + std::to_string(this->_pArray->size()) + "]"); this->parent()->reportWarning(warning, std::move(context)); } private: IJsonHandler* invalid(const std::string& type) { if (this->_arrayIsOpen) { this->reportWarning( type + " value is not allowed in the object array and has been " "replaced with a default value."); this->_pArray->emplace_back(); return this->ignoreAndContinue(); } else { this->reportWarning(type + " is not allowed and has been ignored."); return this->ignoreAndReturnToParent(); } } template static THandler* handlerFactory(Ts&&... args) { return new THandler(std::forward(args)...); } std::vector* _pArray = nullptr; bool _arrayIsOpen = false; std::function _handlerFactory; std::unique_ptr _objectHandler; }; /** * @brief Special case of \ref ArrayJsonHandler for handling arrays of double * values. This will read every scalar value as a double, regardless of whether * it's floating point or not. Attempting to read other values will cause a * warning. */ template <> class CESIUMJSONREADER_API ArrayJsonHandler : public JsonHandler { public: /** @brief The destination type. */ using ValueType = std::vector; ArrayJsonHandler() noexcept : JsonHandler() {} /** * @brief Resets the parent and destination array of this \ref * ArrayJsonHandler. */ void reset(IJsonHandler* pParent, std::vector* pArray) { JsonHandler::reset(pParent); this->_pArray = pArray; this->_arrayIsOpen = false; } virtual IJsonHandler* readNull() override { return this->invalid("A null")->readNull(); } virtual IJsonHandler* readBool(bool b) override { return this->invalid("A bool")->readBool(b); } virtual IJsonHandler* readInt32(int32_t i) override { if (!this->_arrayIsOpen) { return this->invalid("An integer")->readInt32(i); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(static_cast(i)); return this; } virtual IJsonHandler* readUint32(uint32_t i) override { if (!this->_arrayIsOpen) { return this->invalid("An integer")->readUint32(i); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(static_cast(i)); return this; } virtual IJsonHandler* readInt64(int64_t i) override { if (!this->_arrayIsOpen) { return this->invalid("An integer")->readInt64(i); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(static_cast(i)); return this; } virtual IJsonHandler* readUint64(uint64_t i) override { if (!this->_arrayIsOpen) { return this->invalid("An integer")->readUint64(i); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(static_cast(i)); return this; } virtual IJsonHandler* readDouble(double d) override { if (!this->_arrayIsOpen) { return this->invalid("An integer")->readDouble(d); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(d); return this; } virtual IJsonHandler* readString(const std::string_view& str) override { return this->invalid("A string")->readString(str); } virtual IJsonHandler* readObjectStart() override { return this->invalid("An object")->readObjectStart(); } virtual IJsonHandler* readArrayStart() override { if (this->_arrayIsOpen) { return this->invalid("An array")->readArrayStart(); } this->_arrayIsOpen = true; this->_pArray->clear(); return this; } virtual IJsonHandler* readArrayEnd() override { return this->parent(); } virtual void reportWarning( const std::string& warning, std::vector&& context = std::vector()) override { context.push_back( std::string("[") + std::to_string(this->_pArray->size()) + "]"); this->parent()->reportWarning(warning, std::move(context)); } private: IJsonHandler* invalid(const std::string& type) { if (this->_arrayIsOpen) { this->reportWarning( type + " value is not allowed in the double array and has been " "replaced with a default value."); this->_pArray->emplace_back(); return this->ignoreAndContinue(); } else { this->reportWarning(type + " is not allowed and has been ignored."); return this->ignoreAndReturnToParent(); } } std::vector* _pArray = nullptr; bool _arrayIsOpen = false; }; /** * @brief Special case of \ref ArrayJsonHandler for handling arrays of integer * values. Attempting to read other values will cause a warning. */ template class CESIUMJSONREADER_API ArrayJsonHandler> : public JsonHandler { public: /** @brief The destination type. */ using ValueType = std::vector; ArrayJsonHandler() noexcept : JsonHandler() {} /** * @brief Resets the parent and destination array of this \ref * ArrayJsonHandler. */ void reset(IJsonHandler* pParent, std::vector* pArray) { JsonHandler::reset(pParent); this->_pArray = pArray; this->_arrayIsOpen = false; } virtual IJsonHandler* readNull() override { return this->invalid("A null")->readNull(); } virtual IJsonHandler* readBool(bool b) override { return this->invalid("A bool")->readBool(b); } virtual IJsonHandler* readInt32(int32_t i) override { if (!this->_arrayIsOpen) { return this->invalid("An integer")->readInt32(i); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(static_cast(i)); return this; } virtual IJsonHandler* readUint32(uint32_t i) override { if (!this->_arrayIsOpen) { return this->invalid("An integer")->readUint32(i); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(static_cast(i)); return this; } virtual IJsonHandler* readInt64(int64_t i) override { if (!this->_arrayIsOpen) { return this->invalid("An integer")->readInt64(i); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(static_cast(i)); return this; } virtual IJsonHandler* readUint64(uint64_t i) override { if (!this->_arrayIsOpen) { return this->invalid("An integer")->readUint64(i); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(static_cast(i)); return this; } virtual IJsonHandler* readDouble(double d) override { return this->invalid("A double (floating-point)")->readDouble(d); } virtual IJsonHandler* readString(const std::string_view& str) override { return this->invalid("A string")->readString(str); } virtual IJsonHandler* readObjectStart() override { return this->invalid("An object")->readObjectStart(); } virtual IJsonHandler* readArrayStart() override { if (this->_arrayIsOpen) { return this->invalid("An array")->readArrayStart(); } this->_arrayIsOpen = true; this->_pArray->clear(); return this; } virtual IJsonHandler* readArrayEnd() override { return this->parent(); } virtual void reportWarning( const std::string& warning, std::vector&& context = std::vector()) override { context.push_back( std::string("[") + std::to_string(this->_pArray->size()) + "]"); this->parent()->reportWarning(warning, std::move(context)); } private: IJsonHandler* invalid(const std::string& type) { if (this->_arrayIsOpen) { this->reportWarning( type + " value is not allowed in the integer array and has been " "replaced with a default value."); this->_pArray->emplace_back(); return this->ignoreAndContinue(); } else { this->reportWarning(type + " is not allowed and has been ignored."); return this->ignoreAndReturnToParent(); } } std::vector* _pArray = nullptr; bool _arrayIsOpen = false; }; /** * @brief Special case of \ref ArrayJsonHandler for reading arrays of string * values. Attempting to read other values will cause a warning. */ template <> class CESIUMJSONREADER_API ArrayJsonHandler : public JsonHandler { public: /** @brief The destination type. */ using ValueType = std::vector; ArrayJsonHandler() noexcept : JsonHandler() {} /** * @brief Resets the parent and destination array of this \ref * ArrayJsonHandler. */ void reset(IJsonHandler* pParent, std::vector* pArray) { JsonHandler::reset(pParent); this->_pArray = pArray; this->_arrayIsOpen = false; } virtual IJsonHandler* readNull() override { return this->invalid("A null")->readNull(); } virtual IJsonHandler* readBool(bool b) override { return this->invalid("A bool")->readBool(b); } virtual IJsonHandler* readInt32(int32_t i) override { return this->invalid("An integer")->readInt32(i); } virtual IJsonHandler* readUint32(uint32_t i) override { return this->invalid("An integer")->readUint32(i); } virtual IJsonHandler* readInt64(int64_t i) override { return this->invalid("An integer")->readInt64(i); } virtual IJsonHandler* readUint64(uint64_t i) override { return this->invalid("An integer")->readUint64(i); } virtual IJsonHandler* readDouble(double d) override { return this->invalid("A double (floating-point)")->readDouble(d); } virtual IJsonHandler* readObjectStart() override { return this->invalid("An object")->readObjectStart(); } virtual IJsonHandler* readArrayStart() override { if (this->_arrayIsOpen) { return this->invalid("An array")->readArrayStart(); } this->_arrayIsOpen = true; this->_pArray->clear(); return this; } virtual IJsonHandler* readArrayEnd() override { return this->parent(); } virtual IJsonHandler* readString(const std::string_view& str) override { if (!this->_arrayIsOpen) { return this->invalid("A string")->readString(str); } CESIUM_ASSERT(this->_pArray); this->_pArray->emplace_back(str); return this; } virtual void reportWarning( const std::string& warning, std::vector&& context = std::vector()) override { context.push_back( std::string("[") + std::to_string(this->_pArray->size()) + "]"); this->parent()->reportWarning(warning, std::move(context)); } private: IJsonHandler* invalid(const std::string& type) { if (this->_arrayIsOpen) { this->reportWarning( type + " value is not allowed in the string array and has been " "replaced with a default value."); this->_pArray->emplace_back(); return this->ignoreAndContinue(); } else { this->reportWarning(type + " is not allowed and has been ignored."); return this->ignoreAndReturnToParent(); } } std::vector* _pArray = nullptr; bool _arrayIsOpen = false; }; /** * @brief Special case of \ref ArrayJsonHandler for reading arrays of arrays. * Attempting to read other values will cause a warning. * * @tparam T The inner type of the nested array. * @tparam THandler The handler of the inner type of the array. */ template class CESIUMJSONREADER_API ArrayJsonHandler, ArrayJsonHandler> : public JsonHandler { public: /** @brief The destination type. */ using ValueType = std::vector; /** * @brief Creates a new \ref ArrayJsonHandler. * * @param args The arguments passed to the constructor of THandler when it's * instantiated. */ template ArrayJsonHandler(Ts&&... args) noexcept : JsonHandler(), _handlerFactory( std::bind(handlerFactory, std::forward(args)...)), _elementHandler() {} /** * @brief Resets the parent and destination array of this \ref * ArrayJsonHandler. */ void reset(IJsonHandler* pParent, std::vector>* pArray) { JsonHandler::reset(pParent); this->_pArray = pArray; this->_arrayIsOpen = false; this->_elementHandler.reset(this->_handlerFactory()); } virtual IJsonHandler* readNull() override { return this->invalid("A null")->readNull(); } virtual IJsonHandler* readBool(bool b) override { return this->invalid("A bool")->readBool(b); } virtual IJsonHandler* readInt32(int32_t i) override { return this->invalid("An integer")->readInt32(i); } virtual IJsonHandler* readUint32(uint32_t i) override { return this->invalid("An integer")->readUint32(i); } virtual IJsonHandler* readInt64(int64_t i) override { return this->invalid("An integer")->readInt64(i); } virtual IJsonHandler* readUint64(uint64_t i) override { return this->invalid("An integer")->readUint64(i); } virtual IJsonHandler* readDouble(double d) override { return this->invalid("A double (floating-point)")->readDouble(d); } virtual IJsonHandler* readString(const std::string_view& str) override { return this->invalid("A string")->readString(str); } virtual IJsonHandler* readObjectStart() override { return this->invalid("An object")->readObjectStart(); } virtual IJsonHandler* readArrayStart() override { if (this->_arrayIsOpen) { CESIUM_ASSERT(this->_pArray); std::vector& o = this->_pArray->emplace_back(); this->_elementHandler->reset(this, &o); return this->_elementHandler->readArrayStart(); } else { this->_arrayIsOpen = true; this->_pArray->clear(); return this; } } virtual IJsonHandler* readArrayEnd() override { return this->parent(); } virtual void reportWarning( const std::string& warning, std::vector&& context = std::vector()) override { context.push_back( std::string("[") + std::to_string(this->_pArray->size()) + "]"); this->parent()->reportWarning(warning, std::move(context)); } private: IJsonHandler* invalid(const std::string& type) { if (this->_arrayIsOpen) { this->reportWarning( type + " value is not allowed in the array of arrays and has been " "replaced with a default value."); this->_pArray->emplace_back(); return this->ignoreAndContinue(); } else { this->reportWarning(type + " is not allowed and has been ignored."); return this->ignoreAndReturnToParent(); } } template static ArrayJsonHandler* handlerFactory(Ts&&... args) { return new ArrayJsonHandler(std::forward(args)...); } std::vector>* _pArray = nullptr; bool _arrayIsOpen = false; std::function*()> _handlerFactory; std::unique_ptr> _elementHandler; }; } // namespace CesiumJsonReader