| // Copyright 2023 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "jsoncpp_json_serializer.h" | |
| #include "null_json_serializer.h" | |
| #include <cm3p/json/json.h> | |
| #include <cstdlib> | |
| #include <memory> | |
| namespace dap { | |
| namespace json { | |
| JsonCppDeserializer::JsonCppDeserializer(const std::string& str) | |
| : json(new Json::Value(JsonCppDeserializer::parse(str))), ownsJson(true) {} | |
| JsonCppDeserializer::JsonCppDeserializer(const Json::Value* json) | |
| : json(json), ownsJson(false) {} | |
| JsonCppDeserializer::~JsonCppDeserializer() { | |
| if (ownsJson) { | |
| delete json; | |
| } | |
| } | |
| bool JsonCppDeserializer::deserialize(dap::boolean* v) const { | |
| if (!json->isBool()) { | |
| return false; | |
| } | |
| *v = json->asBool(); | |
| return true; | |
| } | |
| bool JsonCppDeserializer::deserialize(dap::integer* v) const { | |
| if (!json->isInt64()) { | |
| return false; | |
| } | |
| *v = json->asInt64(); | |
| return true; | |
| } | |
| bool JsonCppDeserializer::deserialize(dap::number* v) const { | |
| if (!json->isNumeric()) { | |
| return false; | |
| } | |
| *v = json->asDouble(); | |
| return true; | |
| } | |
| bool JsonCppDeserializer::deserialize(dap::string* v) const { | |
| if (!json->isString()) { | |
| return false; | |
| } | |
| *v = json->asString(); | |
| return true; | |
| } | |
| bool JsonCppDeserializer::deserialize(dap::object* v) const { | |
| v->reserve(json->size()); | |
| for (auto i = json->begin(); i != json->end(); i++) { | |
| JsonCppDeserializer d(&*i); | |
| dap::any val; | |
| if (!d.deserialize(&val)) { | |
| return false; | |
| } | |
| (*v)[i.name()] = val; | |
| } | |
| return true; | |
| } | |
| bool JsonCppDeserializer::deserialize(dap::any* v) const { | |
| if (json->isBool()) { | |
| *v = dap::boolean(json->asBool()); | |
| } else if (json->type() == Json::ValueType::realValue) { | |
| // json->isDouble() returns true for integers as well, so we need to | |
| // explicitly look for the realValue type. | |
| *v = dap::number(json->asDouble()); | |
| } else if (json->isInt64()) { | |
| *v = dap::integer(json->asInt64()); | |
| } else if (json->isString()) { | |
| *v = json->asString(); | |
| } else if (json->isObject()) { | |
| dap::object obj; | |
| if (!deserialize(&obj)) { | |
| return false; | |
| } | |
| *v = obj; | |
| } else if (json->isArray()) { | |
| dap::array<any> arr; | |
| if (!deserialize(&arr)) { | |
| return false; | |
| } | |
| *v = arr; | |
| } else if (json->isNull()) { | |
| *v = null(); | |
| } else { | |
| return false; | |
| } | |
| return true; | |
| } | |
| size_t JsonCppDeserializer::count() const { | |
| return json->size(); | |
| } | |
| bool JsonCppDeserializer::array( | |
| const std::function<bool(dap::Deserializer*)>& cb) const { | |
| if (!json->isArray()) { | |
| return false; | |
| } | |
| for (const auto& value : *json) { | |
| JsonCppDeserializer d(&value); | |
| if (!cb(&d)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool JsonCppDeserializer::field( | |
| const std::string& name, | |
| const std::function<bool(dap::Deserializer*)>& cb) const { | |
| if (!json->isObject()) { | |
| return false; | |
| } | |
| auto value = json->find(name.data(), name.data() + name.size()); | |
| if (value == nullptr) { | |
| return cb(&NullDeserializer::instance); | |
| } | |
| JsonCppDeserializer d(value); | |
| return cb(&d); | |
| } | |
| Json::Value JsonCppDeserializer::parse(const std::string& text) { | |
| Json::CharReaderBuilder builder; | |
| auto jsonReader = std::unique_ptr<Json::CharReader>(builder.newCharReader()); | |
| Json::Value json; | |
| std::string error; | |
| if (!jsonReader->parse(text.data(), text.data() + text.size(), &json, | |
| &error)) { | |
| // cppdap expects that the JSON layer does not throw exceptions. | |
| std::abort(); | |
| } | |
| return json; | |
| } | |
| JsonCppSerializer::JsonCppSerializer() | |
| : json(new Json::Value()), ownsJson(true) {} | |
| JsonCppSerializer::JsonCppSerializer(Json::Value* json) | |
| : json(json), ownsJson(false) {} | |
| JsonCppSerializer::~JsonCppSerializer() { | |
| if (ownsJson) { | |
| delete json; | |
| } | |
| } | |
| std::string JsonCppSerializer::dump() const { | |
| Json::StreamWriterBuilder writer; | |
| return Json::writeString(writer, *json); | |
| } | |
| bool JsonCppSerializer::serialize(dap::boolean v) { | |
| *json = (bool)v; | |
| return true; | |
| } | |
| bool JsonCppSerializer::serialize(dap::integer v) { | |
| *json = (Json::LargestInt)v; | |
| return true; | |
| } | |
| bool JsonCppSerializer::serialize(dap::number v) { | |
| *json = (double)v; | |
| return true; | |
| } | |
| bool JsonCppSerializer::serialize(const dap::string& v) { | |
| *json = v; | |
| return true; | |
| } | |
| bool JsonCppSerializer::serialize(const dap::object& v) { | |
| if (!json->isObject()) { | |
| *json = Json::Value(Json::objectValue); | |
| } | |
| for (auto& it : v) { | |
| JsonCppSerializer s(&(*json)[it.first]); | |
| if (!s.serialize(it.second)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool JsonCppSerializer::serialize(const dap::any& v) { | |
| if (v.is<dap::boolean>()) { | |
| *json = (bool)v.get<dap::boolean>(); | |
| } else if (v.is<dap::integer>()) { | |
| *json = (Json::LargestInt)v.get<dap::integer>(); | |
| } else if (v.is<dap::number>()) { | |
| *json = (double)v.get<dap::number>(); | |
| } else if (v.is<dap::string>()) { | |
| *json = v.get<dap::string>(); | |
| } else if (v.is<dap::object>()) { | |
| // reachable if dap::object nested is inside other dap::object | |
| return serialize(v.get<dap::object>()); | |
| } else if (v.is<dap::null>()) { | |
| } else { | |
| // reachable if array or custom serialized type is nested inside other | |
| auto type = get_any_type(v); | |
| auto value = get_any_val(v); | |
| if (type && value) { | |
| return type->serialize(this, value); | |
| } | |
| return false; | |
| } | |
| return true; | |
| } | |
| bool JsonCppSerializer::array(size_t count, | |
| const std::function<bool(dap::Serializer*)>& cb) { | |
| *json = Json::Value(Json::arrayValue); | |
| for (size_t i = 0; i < count; i++) { | |
| JsonCppSerializer s(&(*json)[Json::Value::ArrayIndex(i)]); | |
| if (!cb(&s)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| bool JsonCppSerializer::object( | |
| const std::function<bool(dap::FieldSerializer*)>& cb) { | |
| struct FS : public FieldSerializer { | |
| Json::Value* const json; | |
| FS(Json::Value* json) : json(json) {} | |
| bool field(const std::string& name, const SerializeFunc& cb) override { | |
| JsonCppSerializer s(&(*json)[name]); | |
| auto res = cb(&s); | |
| if (s.removed) { | |
| json->removeMember(name); | |
| } | |
| return res; | |
| } | |
| }; | |
| *json = Json::Value(Json::objectValue); | |
| FS fs{json}; | |
| return cb(&fs); | |
| } | |
| void JsonCppSerializer::remove() { | |
| removed = true; | |
| } | |
| } // namespace json | |
| } // namespace dap |