cdk/parser/json_parser.cc (250 lines of code) (raw):
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is designed to work with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms, as
* designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an additional
* permission to link the program and your derivative works with the
* separately licensed software that they have either included with
* the program or referenced in the documentation.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* https://oss.oracle.com/licenses/universal-foss-exception.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "json_parser.h"
#include <mysql/cdk.h>
PUSH_SYS_WARNINGS_CDK
#include "rapidjson/reader.h"
#include "rapidjson/error/en.h"
POP_SYS_WARNINGS_CDK
#include <stack>
PUSH_SYS_WARNINGS_CDK
#include <stdlib.h>
POP_SYS_WARNINGS_CDK
/*
The maximum absolute value that 64-bit signed integer can have.
For most platforms it is the minimum negative LLONG_MIN.
The absolute value for it cannot be obtained because
ABS(LLONG_MAX) < ABS(LLONG_MIN). Therefore, we define a constant.
*/
#define INTEGER_ABS_MAX 9223372036854775808UL
using namespace parser;
using cdk::string;
using cdk::JSON;
typedef cdk::JSON::Processor Processor;
void JSON_parser::process(Expr_base::Processor &prc) const
{
rapidjson::Reader m_parser;
/*
Note: In-situ parsing could be faster but it would also destroy
contents of m_json and we need it for error reporting.
*/
rapidjson::GenericStringStream<rapidjson::UTF8<char>>
ss(const_cast<char*>(m_json.data()));
/*
struct to be used as handler for rapidjson parser
*/
struct Processor_cvt
{
struct processors
{
Processor *m_obj = nullptr;
Processor::Any_prc* m_key = nullptr;
Processor::Any_prc::List_prc* m_arr = nullptr;
processors(Processor *obj)
{
m_obj = obj;
}
processors(Processor::Any_prc* key)
{
m_key = key;
}
processors(Processor::Any_prc::List_prc* arr)
{
m_arr = arr;
}
};
std::stack<processors> m_stack;
Processor_cvt (Processor &prc)
{
m_stack.push(&prc);
}
bool Null()
{
if (m_stack.empty())
return false;
if (m_stack.top().m_key)
{
m_stack.top().m_key->scalar()->null();
m_stack.pop();
}
else if (m_stack.top().m_arr)
m_stack.top().m_arr->list_el()->scalar()->null();
return true;
}
bool Bool(bool b)
{
if (m_stack.empty())
return false;
if (m_stack.top().m_key)
{
m_stack.top().m_key->scalar()->yesno(b);
m_stack.pop();
}
else if (m_stack.top().m_arr)
m_stack.top().m_arr->list_el()->scalar()->yesno(b);
else
return false;
return true;
}
bool Int(int i)
{
if (m_stack.empty())
return false;
if (m_stack.top().m_key)
{
m_stack.top().m_key->scalar()->num(static_cast<int64_t>(i));
m_stack.pop();
}
else if (m_stack.top().m_arr)
m_stack.top().m_arr->list_el()->scalar()->num(static_cast<int64_t>(i));
else
return false;
return true;
}
bool Uint(unsigned u)
{
if (m_stack.empty())
return false;
if (m_stack.top().m_key)
{
m_stack.top().m_key->scalar()->num(static_cast<uint64_t>(u));
m_stack.pop();
}
else if (m_stack.top().m_arr)
m_stack.top().m_arr->list_el()->scalar()->num(static_cast<uint64_t>(u));
else
return false;
return true;
}
bool Int64(int64_t i)
{
if (m_stack.empty())
return false;
if (m_stack.top().m_key)
{
m_stack.top().m_key->scalar()->num(i);
m_stack.pop();
}
else if (m_stack.top().m_arr)
m_stack.top().m_arr->list_el()->scalar()->num(i);
else
return false;
return true;
}
bool Uint64(uint64_t u)
{
if (m_stack.empty())
return false;
if (m_stack.top().m_key)
{
m_stack.top().m_key->scalar()->num(u);
m_stack.pop();
}
else if (m_stack.top().m_arr)
m_stack.top().m_arr->list_el()->scalar()->num(u);
else
return false;
return true;
}
bool Double(double d)
{
if (m_stack.empty())
return false;
if (m_stack.top().m_key)
{
m_stack.top().m_key->scalar()->num(d);
m_stack.pop();
}
else if (m_stack.top().m_arr)
m_stack.top().m_arr->list_el()->scalar()->num(d);
else
return false;
return true;
}
bool RawNumber(const char* /*str*/,
rapidjson::SizeType /*length*/,
bool /*copy*/)
{
// not needed
return false;
}
bool String(const char* str, rapidjson::SizeType length, bool /*copy*/)
{
if (m_stack.empty())
return false;
if (m_stack.top().m_key)
{
m_stack.top().m_key->scalar()->str(std::string(str, length));
m_stack.pop();
}
else if (m_stack.top().m_arr)
m_stack.top().m_arr->list_el()->scalar()->str(std::string(str, length));
return true;
}
bool Key(const char* str, rapidjson::SizeType length, bool /*copy*/)
{
if (m_stack.empty())
return false;
if (m_stack.top().m_obj)
m_stack.push(m_stack.top().m_obj->key_val(std::string(str, length)));
else
return false;
return true;
}
bool StartObject()
{
if (m_stack.empty())
return false;
if(m_stack.top().m_key)
{
m_stack.push(m_stack.top().m_key->doc());
}
else if (m_stack.top().m_arr)
{
m_stack.push(m_stack.top().m_arr->list_el()->doc());
}
else if (!m_stack.top().m_obj)
return false;
m_stack.top().m_obj->doc_begin();
return true;
}
bool EndObject(rapidjson::SizeType )
{
if(m_stack.empty())
return false;
if (m_stack.top().m_obj)
{
m_stack.top().m_obj->doc_end();
}
m_stack.pop(); // Pop obj
if (!m_stack.empty() && m_stack.top().m_key)
m_stack.pop(); // Pop key
return true;
}
bool StartArray()
{
if (m_stack.empty() )
return false;
if (m_stack.top().m_key)
{
m_stack.push(m_stack.top().m_key->arr());
}
else if (m_stack.top().m_arr)
{
m_stack.push(m_stack.top().m_arr->list_el()->arr());
}
else return false;
m_stack.top().m_arr->list_begin();
return true;
}
bool EndArray(rapidjson::SizeType )
{
if (m_stack.empty() )
return false;
if (!m_stack.top().m_arr)
return false;
m_stack.top().m_arr->list_end();
m_stack.pop();// Pop array
if (!m_stack.empty() && m_stack.top().m_key)
m_stack.pop();// pop key
return true;
}
};
Processor_cvt cvt(prc);
auto error = m_parser.Parse<>(ss, cvt);
if (error.IsError())
{
throw JSON_parser::Error(m_json,
error.Offset(),
rapidjson::GetParseError_En(error.Code()));
}
}
void json_parse(const std::string &json, Processor &dp)
{
JSON_parser parser(json);
parser.process(dp);
}