mysqlshdk/libs/utils/utils_json.cc (242 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.
*
* 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 "mysqlshdk/libs/utils/utils_json.h"
#include <cstring>
#include "mysqlshdk/include/scripting/types.h"
#include "mysqlshdk/libs/utils/dtoa.h"
#include "mysqlshdk/libs/utils/utils_encoding.h"
namespace shcore {
size_t fmt_double(double d, char *buffer, size_t buffer_len) {
return my_gcvt(d, MY_GCVT_ARG_DOUBLE, buffer_len, buffer, NULL);
}
JSON_dumper::JSON_dumper(bool pprint, size_t binary_limit)
: _binary_limit(binary_limit) {
_deep_level = 0;
if (pprint)
_writer = new Pretty_writer();
else
_writer = new Raw_writer();
}
JSON_dumper::~JSON_dumper() {
if (_writer) delete (_writer);
}
void JSON_dumper::append_value(const Value &value) {
switch (value.type) {
case Undefined:
// TODO: Decide what to do on undefineds
break;
case shcore::Null:
_writer->append_null();
break;
case Bool:
_writer->append_bool(value.as_bool());
break;
case Integer:
_writer->append_int64(value.as_int());
break;
case UInteger:
_writer->append_uint64(value.as_uint());
break;
case Float:
_writer->append_float(value.as_double());
break;
case String:
_writer->append_string(value.get_string());
break;
case Object: {
auto object = value.as_object();
if (object)
object->append_json(*this);
else
_writer->append_null();
} break;
case Array: {
Value::Array_type_ref array = value.as_array();
if (array) {
Value::Array_type::const_iterator index, end = array->end();
_writer->start_array();
for (index = array->begin(); index != end; ++index)
append_value(*index);
_writer->end_array();
} else
_writer->append_null();
} break;
case Map: {
Value::Map_type_ref map = value.as_map();
if (map) {
Value::Map_type::const_iterator index, end = map->end();
_writer->start_object();
for (index = map->begin(); index != end; ++index) {
_writer->append_string(index->first);
append_value(index->second);
}
_writer->end_object();
} else
_writer->append_null();
} break;
case MapRef:
// TODO: define what to do with this too
// s_out.append("mapref");
break;
case Function:
value.as_function()->append_json(this);
break;
case Binary: {
std::string encoded;
auto raw_value = value.get_string();
size_t max_length = raw_value.size();
if (_binary_limit > 0) {
// At most binary-limit + 1 bytes should be sent, when the extra byte
// is sent, it will be an indicator for the consumer of the data that
// a truncation happened
max_length = std::min(raw_value.size(), _binary_limit + 1);
}
shcore::encode_base64(static_cast<const unsigned char *>(
static_cast<const void *>(raw_value.c_str())),
max_length, &encoded);
_writer->append_string(encoded);
break;
}
}
}
void JSON_dumper::append_value(const std::string &key, const Value &value) {
_writer->append_string(key);
append_value(value);
}
void JSON_dumper::append(const Value &value) { append_value(value); }
void JSON_dumper::append(const std::string &key, const Value &value) {
append_value(key, value);
}
void JSON_dumper::append(const char *key, const Value &value) {
_writer->append_string(key, std::strlen(key));
append_value(value);
}
void JSON_dumper::append(const Dictionary_t &value) {
append_value(Value(value));
}
void JSON_dumper::append(const std::string &key, const Dictionary_t &value) {
append_value(key, Value(value));
}
void JSON_dumper::append(const char *key, const Dictionary_t &value) {
append(key, Value(value));
}
void JSON_dumper::append(const Array_t &value) { append_value(Value(value)); }
void JSON_dumper::append(const std::string &key, const Array_t &value) {
append_value(key, Value(value));
}
void JSON_dumper::append(const char *key, const Array_t &value) {
append(key, Value(value));
}
void JSON_dumper::append_null() const { _writer->append_null(); }
void JSON_dumper::append_null(const std::string &key) const {
_writer->append_string(key);
_writer->append_null();
}
void JSON_dumper::append_null(const char *key) const {
_writer->append_string(key, std::strlen(key));
append_null();
}
void JSON_dumper::append_bool(bool data) const { _writer->append_bool(data); }
void JSON_dumper::append_bool(const std::string &key, bool data) const {
_writer->append_string(key);
_writer->append_bool(data);
}
void JSON_dumper::append(bool data) const { append_bool(data); }
void JSON_dumper::append(const std::string &key, bool data) const {
append_bool(key, data);
}
void JSON_dumper::append(const char *key, bool data) const {
_writer->append_string(key, std::strlen(key));
append_bool(data);
}
void JSON_dumper::append_int(int data) const { _writer->append_int(data); }
void JSON_dumper::append_int(const std::string &key, int data) const {
_writer->append_string(key);
_writer->append_int(data);
}
void JSON_dumper::append(int data) const { append_int(data); }
void JSON_dumper::append(const std::string &key, int data) const {
append_int(key, data);
}
void JSON_dumper::append(const char *key, int data) const {
_writer->append_string(key, std::strlen(key));
append_int(data);
}
void JSON_dumper::append_int64(int64_t data) const {
_writer->append_int64(data);
}
void JSON_dumper::append_int64(const std::string &key, int64_t data) const {
_writer->append_string(key);
_writer->append_int64(data);
}
void JSON_dumper::append(int64_t data) const { append_int64(data); }
void JSON_dumper::append(const std::string &key, int64_t data) const {
append_int64(key, data);
}
void JSON_dumper::append(const char *key, int64_t data) const {
_writer->append_string(key, std::strlen(key));
append_int64(data);
}
void JSON_dumper::append_uint(unsigned int data) const {
_writer->append_uint(data);
}
void JSON_dumper::append_uint(const std::string &key, unsigned int data) const {
_writer->append_string(key);
_writer->append_uint(data);
}
void JSON_dumper::append(unsigned int data) const { append_uint(data); }
void JSON_dumper::append(const std::string &key, unsigned int data) const {
append_uint(key, data);
}
void JSON_dumper::append(const char *key, unsigned int data) const {
_writer->append_string(key, std::strlen(key));
append_uint(data);
}
void JSON_dumper::append_uint64(uint64_t data) const {
_writer->append_uint64(data);
}
void JSON_dumper::append_uint64(const std::string &key, uint64_t data) const {
_writer->append_string(key);
_writer->append_uint64(data);
}
void JSON_dumper::append(uint64_t data) const { append_uint64(data); }
void JSON_dumper::append(const std::string &key, uint64_t data) const {
append_uint64(key, data);
}
void JSON_dumper::append(const char *key, uint64_t data) const {
_writer->append_string(key, std::strlen(key));
append_uint64(data);
}
void JSON_dumper::append_string(const std::string &data) const {
_writer->append_string(data);
}
void JSON_dumper::append_string(const char *data, size_t length) const {
_writer->append_string(data, length);
}
void JSON_dumper::append_string(const std::string &key,
const std::string &data) const {
_writer->append_string(key);
_writer->append_string(data);
}
void JSON_dumper::append(const std::string &data) const { append_string(data); }
void JSON_dumper::append(const std::string &key,
const std::string &data) const {
append_string(key, data);
}
void JSON_dumper::append(const char *key, const std::string &data) const {
_writer->append_string(key, std::strlen(key));
append_string(data);
}
void JSON_dumper::append_float(double data) const {
_writer->append_float(data);
}
void JSON_dumper::append_float(const std::string &key, double data) const {
_writer->append_string(key);
_writer->append_float(data);
}
void JSON_dumper::append(double data) const { append_float(data); }
void JSON_dumper::append(const std::string &key, double data) const {
append_float(key, data);
}
void JSON_dumper::append(const char *key, double data) const {
_writer->append_string(key, std::strlen(key));
append_float(data);
}
void JSON_dumper::append_json(const std::string &data) const {
rapidjson::Document document;
document.Parse(data.c_str());
_writer->append_document(document);
}
} // namespace shcore