PageRenderTime 86ms CodeModel.GetById 43ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  9#include "JSONVariantParser.h"
 10
 11#include <rapidjson/reader.h>
 12
 13class CJSONVariantParserHandler
 14{
 15public:
 16  explicit CJSONVariantParserHandler(CVariant& parsedObject);
 17
 18  bool Null();
 19  bool Bool(bool b);
 20  bool Int(int i);
 21  bool Uint(unsigned u);
 22  bool Int64(int64_t i);
 23  bool Uint64(uint64_t u);
 24  bool Double(double d);
 25  bool RawNumber(const char* str, rapidjson::SizeType length, bool copy);
 26  bool String(const char* str, rapidjson::SizeType length, bool copy);
 27  bool StartObject();
 28  bool Key(const char* str, rapidjson::SizeType length, bool copy);
 29  bool EndObject(rapidjson::SizeType memberCount);
 30  bool StartArray();
 31  bool EndArray(rapidjson::SizeType elementCount);
 32
 33private:
 34  template <typename... TArgs>
 35  bool Primitive(TArgs... args)
 36  {
 37    PushObject(CVariant(std::forward<TArgs>(args)...));
 38    PopObject();
 39
 40    return true;
 41  }
 42
 43  void PushObject(CVariant variant);
 44  void PopObject();
 45
 46  CVariant& m_parsedObject;
 47  std::vector<CVariant *> m_parse;
 48  std::string m_key;
 49
 50  enum class PARSE_STATUS
 51  {
 52    Variable,
 53    Array,
 54    Object
 55  };
 56  PARSE_STATUS m_status;
 57};
 58
 59CJSONVariantParserHandler::CJSONVariantParserHandler(CVariant& parsedObject)
 60  : m_parsedObject(parsedObject),
 61    m_parse(),
 62    m_key(),
 63    m_status(PARSE_STATUS::Variable)
 64{ }
 65
 66bool CJSONVariantParserHandler::Null()
 67{
 68  PushObject(CVariant::ConstNullVariant);
 69  PopObject();
 70
 71  return true;
 72}
 73
 74bool CJSONVariantParserHandler::Bool(bool b)
 75{
 76  return Primitive(b);
 77}
 78
 79bool CJSONVariantParserHandler::Int(int i)
 80{
 81  return Primitive(i);
 82}
 83
 84bool CJSONVariantParserHandler::Uint(unsigned u)
 85{
 86  return Primitive(u);
 87}
 88
 89bool CJSONVariantParserHandler::Int64(int64_t i)
 90{
 91  return Primitive(i);
 92}
 93
 94bool CJSONVariantParserHandler::Uint64(uint64_t u)
 95{
 96  return Primitive(u);
 97}
 98
 99bool CJSONVariantParserHandler::Double(double d)
100{
101  return Primitive(d);
102}
103
104bool CJSONVariantParserHandler::RawNumber(const char* str, rapidjson::SizeType length, bool copy)
105{
106  return Primitive(str, length);
107}
108
109bool CJSONVariantParserHandler::String(const char* str, rapidjson::SizeType length, bool copy)
110{
111  return Primitive(str, length);
112}
113
114bool CJSONVariantParserHandler::StartObject()
115{
116  PushObject(CVariant::VariantTypeObject);
117
118  return true;
119}
120
121bool CJSONVariantParserHandler::Key(const char* str, rapidjson::SizeType length, bool copy)
122{
123  m_key = std::string(str, 0, length);
124
125  return true;
126}
127
128bool CJSONVariantParserHandler::EndObject(rapidjson::SizeType memberCount)
129{
130  PopObject();
131
132  return true;
133}
134
135bool CJSONVariantParserHandler::StartArray()
136{
137  PushObject(CVariant::VariantTypeArray);
138
139  return true;
140}
141
142bool CJSONVariantParserHandler::EndArray(rapidjson::SizeType elementCount)
143{
144  PopObject();
145
146  return true;
147}
148
149void CJSONVariantParserHandler::PushObject(CVariant variant)
150{
151  if (m_status == PARSE_STATUS::Object)
152  {
153    (*m_parse[m_parse.size() - 1])[m_key] = variant;
154    m_parse.push_back(&(*m_parse[m_parse.size() - 1])[m_key]);
155  }
156  else if (m_status == PARSE_STATUS::Array)
157  {
158    CVariant *temp = m_parse[m_parse.size() - 1];
159    temp->push_back(variant);
160    m_parse.push_back(&(*temp)[temp->size() - 1]);
161  }
162  else if (m_parse.empty())
163    m_parse.push_back(new CVariant(variant));
164
165  if (variant.isObject())
166    m_status = PARSE_STATUS::Object;
167  else if (variant.isArray())
168    m_status = PARSE_STATUS::Array;
169  else
170    m_status = PARSE_STATUS::Variable;
171}
172
173void CJSONVariantParserHandler::PopObject()
174{
175  CVariant *variant = m_parse[m_parse.size() - 1];
176  m_parse.pop_back();
177
178  if (!m_parse.empty())
179  {
180    variant = m_parse[m_parse.size() - 1];
181    if (variant->isObject())
182      m_status = PARSE_STATUS::Object;
183    else if (variant->isArray())
184      m_status = PARSE_STATUS::Array;
185    else
186      m_status = PARSE_STATUS::Variable;
187  }
188  else
189  {
190    m_parsedObject = *variant;
191    delete variant;
192
193    m_status = PARSE_STATUS::Variable;
194  }
195}
196
197bool CJSONVariantParser::Parse(const char* json, CVariant& data)
198{
199  if (json == nullptr)
200    return false;
201
202  rapidjson::Reader reader;
203  rapidjson::StringStream stringStream(json);
204
205  CJSONVariantParserHandler handler(data);
206  // use kParseIterativeFlag to eliminate possible stack overflow
207  // from json parsing via reentrant calls
208  if (reader.Parse<rapidjson::kParseIterativeFlag>(stringStream, handler))
209    return true;
210
211  return false;
212}
213
214bool CJSONVariantParser::Parse(const std::string& json, CVariant& data)
215{
216  return Parse(json.c_str(), data);
217}