/xbmc/utils/JSONVariantParser.cpp

http://github.com/xbmc/xbmc · C++ · 217 lines · 168 code · 40 blank · 9 comment · 17 complexity · a0892c099c36b11107307cead3fb27f2 MD5 · raw file

  1. /*
  2. * Copyright (C) 2005-2018 Team Kodi
  3. * This file is part of Kodi - https://kodi.tv
  4. *
  5. * SPDX-License-Identifier: GPL-2.0-or-later
  6. * See LICENSES/README.md for more information.
  7. */
  8. #include "JSONVariantParser.h"
  9. #include <rapidjson/reader.h>
  10. class CJSONVariantParserHandler
  11. {
  12. public:
  13. explicit CJSONVariantParserHandler(CVariant& parsedObject);
  14. bool Null();
  15. bool Bool(bool b);
  16. bool Int(int i);
  17. bool Uint(unsigned u);
  18. bool Int64(int64_t i);
  19. bool Uint64(uint64_t u);
  20. bool Double(double d);
  21. bool RawNumber(const char* str, rapidjson::SizeType length, bool copy);
  22. bool String(const char* str, rapidjson::SizeType length, bool copy);
  23. bool StartObject();
  24. bool Key(const char* str, rapidjson::SizeType length, bool copy);
  25. bool EndObject(rapidjson::SizeType memberCount);
  26. bool StartArray();
  27. bool EndArray(rapidjson::SizeType elementCount);
  28. private:
  29. template <typename... TArgs>
  30. bool Primitive(TArgs... args)
  31. {
  32. PushObject(CVariant(std::forward<TArgs>(args)...));
  33. PopObject();
  34. return true;
  35. }
  36. void PushObject(CVariant variant);
  37. void PopObject();
  38. CVariant& m_parsedObject;
  39. std::vector<CVariant *> m_parse;
  40. std::string m_key;
  41. enum class PARSE_STATUS
  42. {
  43. Variable,
  44. Array,
  45. Object
  46. };
  47. PARSE_STATUS m_status;
  48. };
  49. CJSONVariantParserHandler::CJSONVariantParserHandler(CVariant& parsedObject)
  50. : m_parsedObject(parsedObject),
  51. m_parse(),
  52. m_key(),
  53. m_status(PARSE_STATUS::Variable)
  54. { }
  55. bool CJSONVariantParserHandler::Null()
  56. {
  57. PushObject(CVariant::ConstNullVariant);
  58. PopObject();
  59. return true;
  60. }
  61. bool CJSONVariantParserHandler::Bool(bool b)
  62. {
  63. return Primitive(b);
  64. }
  65. bool CJSONVariantParserHandler::Int(int i)
  66. {
  67. return Primitive(i);
  68. }
  69. bool CJSONVariantParserHandler::Uint(unsigned u)
  70. {
  71. return Primitive(u);
  72. }
  73. bool CJSONVariantParserHandler::Int64(int64_t i)
  74. {
  75. return Primitive(i);
  76. }
  77. bool CJSONVariantParserHandler::Uint64(uint64_t u)
  78. {
  79. return Primitive(u);
  80. }
  81. bool CJSONVariantParserHandler::Double(double d)
  82. {
  83. return Primitive(d);
  84. }
  85. bool CJSONVariantParserHandler::RawNumber(const char* str, rapidjson::SizeType length, bool copy)
  86. {
  87. return Primitive(str, length);
  88. }
  89. bool CJSONVariantParserHandler::String(const char* str, rapidjson::SizeType length, bool copy)
  90. {
  91. return Primitive(str, length);
  92. }
  93. bool CJSONVariantParserHandler::StartObject()
  94. {
  95. PushObject(CVariant::VariantTypeObject);
  96. return true;
  97. }
  98. bool CJSONVariantParserHandler::Key(const char* str, rapidjson::SizeType length, bool copy)
  99. {
  100. m_key = std::string(str, 0, length);
  101. return true;
  102. }
  103. bool CJSONVariantParserHandler::EndObject(rapidjson::SizeType memberCount)
  104. {
  105. PopObject();
  106. return true;
  107. }
  108. bool CJSONVariantParserHandler::StartArray()
  109. {
  110. PushObject(CVariant::VariantTypeArray);
  111. return true;
  112. }
  113. bool CJSONVariantParserHandler::EndArray(rapidjson::SizeType elementCount)
  114. {
  115. PopObject();
  116. return true;
  117. }
  118. void CJSONVariantParserHandler::PushObject(CVariant variant)
  119. {
  120. if (m_status == PARSE_STATUS::Object)
  121. {
  122. (*m_parse[m_parse.size() - 1])[m_key] = variant;
  123. m_parse.push_back(&(*m_parse[m_parse.size() - 1])[m_key]);
  124. }
  125. else if (m_status == PARSE_STATUS::Array)
  126. {
  127. CVariant *temp = m_parse[m_parse.size() - 1];
  128. temp->push_back(variant);
  129. m_parse.push_back(&(*temp)[temp->size() - 1]);
  130. }
  131. else if (m_parse.empty())
  132. m_parse.push_back(new CVariant(variant));
  133. if (variant.isObject())
  134. m_status = PARSE_STATUS::Object;
  135. else if (variant.isArray())
  136. m_status = PARSE_STATUS::Array;
  137. else
  138. m_status = PARSE_STATUS::Variable;
  139. }
  140. void CJSONVariantParserHandler::PopObject()
  141. {
  142. CVariant *variant = m_parse[m_parse.size() - 1];
  143. m_parse.pop_back();
  144. if (!m_parse.empty())
  145. {
  146. variant = m_parse[m_parse.size() - 1];
  147. if (variant->isObject())
  148. m_status = PARSE_STATUS::Object;
  149. else if (variant->isArray())
  150. m_status = PARSE_STATUS::Array;
  151. else
  152. m_status = PARSE_STATUS::Variable;
  153. }
  154. else
  155. {
  156. m_parsedObject = *variant;
  157. delete variant;
  158. m_status = PARSE_STATUS::Variable;
  159. }
  160. }
  161. bool CJSONVariantParser::Parse(const char* json, CVariant& data)
  162. {
  163. if (json == nullptr)
  164. return false;
  165. rapidjson::Reader reader;
  166. rapidjson::StringStream stringStream(json);
  167. CJSONVariantParserHandler handler(data);
  168. // use kParseIterativeFlag to eliminate possible stack overflow
  169. // from json parsing via reentrant calls
  170. if (reader.Parse<rapidjson::kParseIterativeFlag>(stringStream, handler))
  171. return true;
  172. return false;
  173. }
  174. bool CJSONVariantParser::Parse(const std::string& json, CVariant& data)
  175. {
  176. return Parse(json.c_str(), data);
  177. }