summaryrefslogtreecommitdiffstats
path: root/xbmc/utils/JSONVariantParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/utils/JSONVariantParser.cpp')
-rw-r--r--xbmc/utils/JSONVariantParser.cpp219
1 files changed, 219 insertions, 0 deletions
diff --git a/xbmc/utils/JSONVariantParser.cpp b/xbmc/utils/JSONVariantParser.cpp
new file mode 100644
index 0000000..493abfd
--- /dev/null
+++ b/xbmc/utils/JSONVariantParser.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "JSONVariantParser.h"
+
+#include <rapidjson/reader.h>
+
+class CJSONVariantParserHandler
+{
+public:
+ explicit CJSONVariantParserHandler(CVariant& parsedObject);
+
+ bool Null();
+ bool Bool(bool b);
+ bool Int(int i);
+ bool Uint(unsigned u);
+ bool Int64(int64_t i);
+ bool Uint64(uint64_t u);
+ bool Double(double d);
+ bool RawNumber(const char* str, rapidjson::SizeType length, bool copy);
+ bool String(const char* str, rapidjson::SizeType length, bool copy);
+ bool StartObject();
+ bool Key(const char* str, rapidjson::SizeType length, bool copy);
+ bool EndObject(rapidjson::SizeType memberCount);
+ bool StartArray();
+ bool EndArray(rapidjson::SizeType elementCount);
+
+private:
+ template <typename... TArgs>
+ bool Primitive(TArgs... args)
+ {
+ PushObject(CVariant(std::forward<TArgs>(args)...));
+ PopObject();
+
+ return true;
+ }
+
+ void PushObject(const CVariant& variant);
+ void PopObject();
+
+ CVariant& m_parsedObject;
+ std::vector<CVariant *> m_parse;
+ std::string m_key;
+ CVariant m_root;
+
+ enum class PARSE_STATUS
+ {
+ Variable,
+ Array,
+ Object
+ };
+ PARSE_STATUS m_status;
+};
+
+CJSONVariantParserHandler::CJSONVariantParserHandler(CVariant& parsedObject)
+ : m_parsedObject(parsedObject),
+ m_parse(),
+ m_key(),
+ m_status(PARSE_STATUS::Variable)
+{ }
+
+bool CJSONVariantParserHandler::Null()
+{
+ PushObject(CVariant::ConstNullVariant);
+ PopObject();
+
+ return true;
+}
+
+bool CJSONVariantParserHandler::Bool(bool b)
+{
+ return Primitive(b);
+}
+
+bool CJSONVariantParserHandler::Int(int i)
+{
+ return Primitive(i);
+}
+
+bool CJSONVariantParserHandler::Uint(unsigned u)
+{
+ return Primitive(u);
+}
+
+bool CJSONVariantParserHandler::Int64(int64_t i)
+{
+ return Primitive(i);
+}
+
+bool CJSONVariantParserHandler::Uint64(uint64_t u)
+{
+ return Primitive(u);
+}
+
+bool CJSONVariantParserHandler::Double(double d)
+{
+ return Primitive(d);
+}
+
+bool CJSONVariantParserHandler::RawNumber(const char* str, rapidjson::SizeType length, bool copy)
+{
+ return Primitive(str, length);
+}
+
+bool CJSONVariantParserHandler::String(const char* str, rapidjson::SizeType length, bool copy)
+{
+ return Primitive(str, length);
+}
+
+bool CJSONVariantParserHandler::StartObject()
+{
+ PushObject(CVariant::VariantTypeObject);
+
+ return true;
+}
+
+bool CJSONVariantParserHandler::Key(const char* str, rapidjson::SizeType length, bool copy)
+{
+ m_key = std::string(str, 0, length);
+
+ return true;
+}
+
+bool CJSONVariantParserHandler::EndObject(rapidjson::SizeType memberCount)
+{
+ PopObject();
+
+ return true;
+}
+
+bool CJSONVariantParserHandler::StartArray()
+{
+ PushObject(CVariant::VariantTypeArray);
+
+ return true;
+}
+
+bool CJSONVariantParserHandler::EndArray(rapidjson::SizeType elementCount)
+{
+ PopObject();
+
+ return true;
+}
+
+void CJSONVariantParserHandler::PushObject(const CVariant& variant)
+{
+ if (m_status == PARSE_STATUS::Object)
+ {
+ (*m_parse[m_parse.size() - 1])[m_key] = variant;
+ m_parse.push_back(&(*m_parse[m_parse.size() - 1])[m_key]);
+ }
+ else if (m_status == PARSE_STATUS::Array)
+ {
+ CVariant *temp = m_parse[m_parse.size() - 1];
+ temp->push_back(variant);
+ m_parse.push_back(&(*temp)[temp->size() - 1]);
+ }
+ else if (m_parse.empty())
+ {
+ m_root = variant;
+ m_parse.push_back(&m_root);
+ }
+
+ if (variant.isObject())
+ m_status = PARSE_STATUS::Object;
+ else if (variant.isArray())
+ m_status = PARSE_STATUS::Array;
+ else
+ m_status = PARSE_STATUS::Variable;
+}
+
+void CJSONVariantParserHandler::PopObject()
+{
+ CVariant *variant = m_parse[m_parse.size() - 1];
+ m_parse.pop_back();
+
+ if (!m_parse.empty())
+ {
+ variant = m_parse[m_parse.size() - 1];
+ if (variant->isObject())
+ m_status = PARSE_STATUS::Object;
+ else if (variant->isArray())
+ m_status = PARSE_STATUS::Array;
+ else
+ m_status = PARSE_STATUS::Variable;
+ }
+ else
+ {
+ m_parsedObject = *variant;
+ m_status = PARSE_STATUS::Variable;
+ }
+}
+
+bool CJSONVariantParser::Parse(const char* json, CVariant& data)
+{
+ if (json == nullptr)
+ return false;
+
+ rapidjson::Reader reader;
+ rapidjson::StringStream stringStream(json);
+
+ CJSONVariantParserHandler handler(data);
+ // use kParseIterativeFlag to eliminate possible stack overflow
+ // from json parsing via reentrant calls
+ if (reader.Parse<rapidjson::kParseIterativeFlag>(stringStream, handler))
+ return true;
+
+ return false;
+}
+
+bool CJSONVariantParser::Parse(const std::string& json, CVariant& data)
+{
+ return Parse(json.c_str(), data);
+}