diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp index 42a08d9392f651f0676320685ffc6b06ca104dd8..b3c1ca3d02db51e160c95c9a6c9e032fab8f66af 100644 --- a/indra/llcommon/llsdjson.cpp +++ b/indra/llcommon/llsdjson.cpp @@ -33,44 +33,45 @@ #include "llerror.h" +#include <boost/json/src.hpp> //========================================================================= -LLSD LlsdFromJson(const nlohmann::json &val) +LLSD LlsdFromJson(const boost::json::value& val) { LLSD result; - switch (val.type()) + switch (val.kind()) { default: - case nlohmann::json::value_t::null: + case boost::json::kind::null: break; - case nlohmann::json::value_t::number_integer: - result = LLSD(val.get<LLSD::Integer>()); + case boost::json::kind::int64: + result = LLSD(val.as_int64()); break; - case nlohmann::json::value_t::number_unsigned: - result = LLSD(val.get<LLSD::Integer>()); + case boost::json::kind::uint64: + result = LLSD(val.as_uint64()); break; - case nlohmann::json::value_t::number_float: - result = LLSD(val.get<LLSD::Real>()); + case boost::json::kind::double_: + result = LLSD(val.as_double()); break; - case nlohmann::json::value_t::string: - result = LLSD(val.get<LLSD::String>()); + case boost::json::kind::string: + result = LLSD(std::string(val.as_string())); break; - case nlohmann::json::value_t::boolean: - result = LLSD(val.get<LLSD::Boolean>()); + case boost::json::kind::bool_: + result = LLSD(val.as_bool()); break; - case nlohmann::json::value_t::array: + case boost::json::kind::array: result = LLSD::emptyArray(); - for (const auto &element : val) + for (const auto &element : val.as_array()) { result.append(LlsdFromJson(element)); } break; - case nlohmann::json::value_t::object: + case boost::json::kind::object: result = LLSD::emptyMap(); - for (auto it = val.cbegin(), end = val.cend(); it != end; ++it) + for (const auto& element : val.as_object()) { - result[it.key()] = LlsdFromJson(it.value()); + result[element.key()] = LlsdFromJson(element.value()); } break; } @@ -78,9 +79,9 @@ LLSD LlsdFromJson(const nlohmann::json &val) } //========================================================================= -nlohmann::json LlsdToJson(const LLSD &val) +boost::json::value LlsdToJson(const LLSD &val) { - nlohmann::json result; + boost::json::value result; switch (val.type()) { @@ -103,17 +104,23 @@ nlohmann::json LlsdToJson(const LLSD &val) result = val.asString(); break; case LLSD::TypeMap: - for (auto it = val.beginMap(), it_end = val.endMap(); it != it_end; ++it) + { + boost::json::object& obj = result.emplace_object(); + for (const auto& llsd_dat : val.asMap()) { - result[it->first] = LlsdToJson(it->second); + obj[llsd_dat.first] = LlsdToJson(llsd_dat.second); } break; + } case LLSD::TypeArray: - for (auto it = val.beginArray(), end = val.endArray(); it != end; ++it) + { + boost::json::array& json_array = result.emplace_array(); + for (const auto& llsd_dat : val.asArray()) { - result.push_back(LlsdToJson(*it)); + json_array.push_back(LlsdToJson(llsd_dat)); } break; + } case LLSD::TypeBinary: default: LL_ERRS("LlsdToJson") << "Unsupported conversion to JSON from LLSD type (" << val.type() << ")." << LL_ENDL; diff --git a/indra/llcommon/llsdjson.h b/indra/llcommon/llsdjson.h index 19f4883053c488e591b259ebce944a8e0734f51d..140cc53748f3e3c42d8a812130fdb0a3fdf0d979 100644 --- a/indra/llcommon/llsdjson.h +++ b/indra/llcommon/llsdjson.h @@ -30,7 +30,7 @@ #include "llsd.h" -#include <nlohmann/json.hpp> +#include <boost/json.hpp> /// Convert a parsed JSON structure into LLSD maintaining member names and /// array indexes. @@ -49,7 +49,7 @@ /// /// For maps and arrays child entries will be converted and added to the structure. /// Order is preserved for an array but not for objects. -LLSD LlsdFromJson(const nlohmann::json &val); +LLSD LlsdFromJson(const boost::json::value &val); /// Convert an LLSD object into Parsed JSON object maintaining member names and /// array indexs. @@ -68,6 +68,6 @@ LLSD LlsdFromJson(const nlohmann::json &val); /// TypeMap | object /// TypeArray | array /// TypeBinary | unsupported -nlohmann::json LlsdToJson(const LLSD &val); +boost::json::value LlsdToJson(const LLSD &val); #endif // LL_LLSDJSON_H diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 8fc1906d8ddbdab03684ce230643c9b11ad9d170..c2fa12543910078d6b37f5f17df5d867c229125d 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -30,7 +30,6 @@ #include <sstream> #include <algorithm> #include <iterator> -#include <nlohmann/json.hpp> // JSON #include <utility> #include "llcorehttputil.h" #include "llhttpconstants.h" @@ -585,20 +584,12 @@ LLSD HttpCoroJSONHandler::handleSuccess(LLCore::HttpResponse * response, LLCore: } LLCore::BufferArrayStream bas(body); - nlohmann::json jsonRoot; - try - { - bas >> jsonRoot; - } - catch (const nlohmann::json::exception& e) - { // deserialization failed. Record the reason and pass back an empty map for markup. - status = LLCore::HttpStatus(499, std::string(e.what())); - return result; - } - catch (const std::runtime_error& e) + boost::json::error_code ec; + boost::json::value jsonRoot = boost::json::parse(bas, ec); + if(ec.failed()) { // deserialization failed. Record the reason and pass back an empty map for markup. - status = LLCore::HttpStatus(499, std::string(e.what())); + status = LLCore::HttpStatus(499, std::string(ec.what())); return result; } @@ -618,19 +609,11 @@ LLSD HttpCoroJSONHandler::parseBody(LLCore::HttpResponse *response, bool &succes } LLCore::BufferArrayStream bas(body); - nlohmann::json jsonRoot; - try + boost::json::error_code ec; + boost::json::value jsonRoot = boost::json::parse(bas, ec); + if (ec.failed()) { - bas >> jsonRoot; - } - catch (const nlohmann::json::exception&) - { - success = false; - return LLSD(); - } - catch (const std::runtime_error&) - { success = false; return LLSD(); } @@ -812,8 +795,8 @@ LLSD HttpCoroutineAdapter::postJsonAndSuspend(LLCore::HttpRequest::ptr_t request { LLCore::BufferArrayStream outs(rawbody.get()); - nlohmann::json root = LlsdToJson(body); - std::string value = root.dump(); + auto root = LlsdToJson(body); + std::string value = boost::json::serialize(root); LL_WARNS("Http::post") << "JSON Generates: \"" << value << "\"" << LL_ENDL; @@ -871,8 +854,8 @@ LLSD HttpCoroutineAdapter::putJsonAndSuspend(LLCore::HttpRequest::ptr_t request, { LLCore::BufferArrayStream outs(rawbody.get()); - nlohmann::json root = LlsdToJson(body); - std::string value = root.dump(); + auto root = LlsdToJson(body); + std::string value = boost::json::serialize(root); LL_WARNS("Http::put") << "JSON Generates: \"" << value << "\"" << LL_ENDL; outs << value; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index c1d65363307405a8d8c55200e8aeb23ad91158a2..1eabc917d7cf2de0209b0bb14905a451820bc675 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -123,7 +123,7 @@ #include "llviewercontrol.h" #include "llpresetsmanager.h" -#include <nlohmann/json.hpp> +#include <boost/json.hpp> #include <utility> #include "llsearchableui.h" @@ -668,29 +668,30 @@ bool LLFloaterPreference::handleRemoveGridCB(const LLSD& notification, const LLS skin_t manifestFromJson(const std::string& filename, const ESkinType type) { skin_t skin; - nlohmann::json root; llifstream in; in.open(filename); if (in.is_open()) { - try + boost::json::error_code ec; + auto root = boost::json::parse(in, ec); + if (!ec.failed() && root.is_object()) { - in >> root; - skin.mName = root.value("name", "Unknown"); - skin.mAuthor = root.value("author", "Unknown"); - skin.mUrl = root.value("url", "Unknown"); - skin.mCompatVer = root.value("compatibility", "Unknown"); - skin.mDate = LLDate(root.value("date", LLDate::now().asString())); - skin.mNotes = root.value("notes", ""); + auto jobj = root.as_object(); + skin.mName = jobj.contains("name") ? boost::json::value_to<std::string>(jobj.at("name")) : "Unknown"; + skin.mAuthor = jobj.contains("author") ? boost::json::value_to<std::string>(jobj.at("author")) : LLTrans::getString("Unknown"); + skin.mUrl = jobj.contains("url") ? boost::json::value_to<std::string>(jobj.at("url")) : LLTrans::getString("Unknown"); + skin.mCompatVer = jobj.contains("compatibility") ? boost::json::value_to<std::string>(jobj.at("compatibility")) : LLTrans::getString("Unknown"); + skin.mDate = jobj.contains("date") ? LLDate(boost::json::value_to<std::string>(jobj.at("date"))) : LLDate::now(); + skin.mNotes = jobj.contains("notes") ? boost::json::value_to<std::string>(jobj.at("notes")) : ""; // If it's a system skin, the compatability version is always the current build if (type == SYSTEM_SKIN) { skin.mCompatVer = LLVersionInfo::instance().getShortVersion(); } } - catch(const nlohmann::json::exception& e) + else { - LL_WARNS() << "Failed to parse " << filename << ": " << e.what() << LL_ENDL; + LL_WARNS() << "Failed to parse " << filename << ": " << ec.message() << LL_ENDL; } in.close(); } @@ -784,11 +785,12 @@ void LLFloaterPreference::onAddSkinCallback(const std::vector<std::string>& file ss << std::string(const_cast<const char*>(buf.get()), buf_size); buf.reset(); - nlohmann::json root; - try + boost::json::error_code ec; + auto root = boost::json::parse(ss, ec); + if (!ec.failed() && root.is_object()) { - ss >> root; - const std::string& name = root.value("name", "Unknown"); + const auto& jobj = root.as_object(); + const std::string& name = jobj.contains("name") ? boost::json::value_to<std::string>(jobj.at("name")) : "Unknown"; std::string pathname = gDirUtilp->add(gDirUtilp->getOSUserAppDir(), "skins"); if (!gDirUtilp->fileExists(pathname)) { @@ -809,7 +811,7 @@ void LLFloaterPreference::onAddSkinCallback(const std::vector<std::string>& file LLNotificationsUtil::add("AddSkinSuccess", LLSD().with("PACKAGE", name)); } } - catch(const nlohmann::json::exception&) + else { LLNotificationsUtil::add("AddSkinCantParseManifest", LLSD().with("PACKAGE", package)); } diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index d090dce32b622e92e3eb2f9cacac133deee36801..7da4b0b165ce94b172fc99590117fde777fd3e07 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -40,7 +40,7 @@ #include "llurlregistry.h" #include "stringize.h" -#include <nlohmann/json.hpp> +#include <boost/json.hpp> static const std::string AZURE_NOTRANSLATE_OPENING_TAG("<div translate=\"no\">"); static const std::string AZURE_NOTRANSLATE_CLOSING_TAG("</div>"); @@ -346,11 +346,11 @@ class LLGoogleTranslationHandler : public LLTranslationAPIHandler private: static void parseErrorResponse( - const nlohmann::json &root, + const boost::json::value &root, int &status, std::string &err_msg); static bool parseTranslation( - const nlohmann::json &root, + const boost::json::value&root, std::string &translation, std::string &detected_lang); static std::string getAPIKey(); @@ -399,17 +399,13 @@ bool LLGoogleTranslationHandler::parseResponse( std::string& detected_lang, std::string& err_msg) const { - std::stringstream stream(body); - nlohmann::json root; - try + boost::json::error_code ec; + boost::json::value root = boost::json::parse(body, ec); + if (ec.failed()) { - stream >> root; + err_msg = ec.what(); + return false; } - catch(nlohmann::json::exception &e) - { - err_msg = e.what(); - return false; - } if (!root.is_object()) // empty response? should not happen { @@ -435,48 +431,49 @@ bool LLGoogleTranslationHandler::isConfigured() const // static void LLGoogleTranslationHandler::parseErrorResponse( - const nlohmann::json &root, + const boost::json::value &root, int &status, std::string &err_msg) { - const nlohmann::json &error = root.at("error"); - if (!error.is_object() || error.find("message") == error.end() || error.find("code") == error.end()) + boost::json::error_code ec; + const boost::json::value &error = root.at("error"); + if (!error.is_object() || !error.as_object().contains("message") || !error.as_object().contains("code")) { return; } - err_msg = error["message"].get<std::string>(); - status = error.at("code"); + err_msg = boost::json::value_to<std::string>(error.at("message")); + status = boost::json::value_to<int>(error.at("code")); } // static bool LLGoogleTranslationHandler::parseTranslation( - const nlohmann::json &root, + const boost::json::value &root, std::string &translation, std::string &detected_lang) { // Json is prone to aborting the program on failed assertions, // so be super-careful and verify the response format. - const nlohmann::json &data = root.at("data"); - if (!data.is_object() || data.find("translations") == data.end()) + const boost::json::value &data = root.at("data"); + if (!data.is_object() || !data.as_object().contains("translations")) { return false; } - const nlohmann::json &translations = data["translations"]; - if (!translations.is_array() || translations.empty()) + const boost::json::value&translations = data.at("translations"); + if (!translations.is_array() || translations.as_array().empty()) { return false; } - const nlohmann::json &first = translations[0]; - if (!first.is_object() || first.find("translatedText") == first.end()) + const boost::json::value &first = translations.at(0); + if (!first.is_object() || !first.as_object().contains("translatedText")) { return false; } - translation = first["translatedText"].get<std::string>(); - detected_lang = first.value("detectedSourceLanguage", ""); + translation = boost::json::value_to<std::string>(first.at("translatedText")); + detected_lang = first.as_object().contains("detectedSourceLanguage") ? boost::json::value_to<std::string>(first.at("detectedSourceLanguage")) : ""; return true; } @@ -658,17 +655,13 @@ bool LLAzureTranslationHandler::checkVerificationResponse( // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}" // But for now just verify response is a valid json - std::stringstream stream(response["error_body"].asString()); - nlohmann::json root; - try + boost::json::error_code ec; + boost::json::value root = boost::json::parse(response["error_body"].asString(), ec); + if (ec.failed()) { - stream >> root; + LL_DEBUGS("Translate") << "Failed to parse error_body:" << ec.what() << LL_ENDL; + return false; } - catch(nlohmann::json::exception &e) - { - LL_DEBUGS("Translate") << "Failed to parse error_body:" << e.what() << LL_ENDL; - return false; - } return true; } @@ -692,16 +685,13 @@ bool LLAzureTranslationHandler::parseResponse( //Example: // "[{\"detectedLanguage\":{\"language\":\"en\",\"score\":1.0},\"translations\":[{\"text\":\"Hello, what is your name?\",\"to\":\"en\"}]}]" - nlohmann::json root; - try + boost::json::error_code ec; + boost::json::value root = boost::json::parse(body, ec); + if (ec.failed()) { - root = nlohmann::json::parse(body); - } - catch(nlohmann::json::exception &e) - { - err_msg = e.what(); + err_msg = ec.what(); return false; - } + } if (!root.is_array()) // empty response? should not happen { @@ -710,34 +700,34 @@ bool LLAzureTranslationHandler::parseResponse( // Request succeeded, extract translation from the response. - const nlohmann::json& data = root[0U]; + const boost::json::value& data = root.at(0U); if (!data.is_object() - || data.find("detectedLanguage") == data.end() - || data.find("translations") == data.end()) + || !data.as_object().contains("detectedLanguage") + || !data.as_object().contains("translations")) { return false; } - const nlohmann::json& detectedLanguage = data["detectedLanguage"]; - if (!detectedLanguage.is_object() || detectedLanguage.find("language") == detectedLanguage.end()) + const boost::json::value& detectedLanguage = data.at("detectedLanguage"); + if (!detectedLanguage.is_object() || !detectedLanguage.as_object().contains("language")) { return false; } - detected_lang = detectedLanguage["language"].get<std::string>(); + detected_lang = boost::json::value_to<std::string>(detectedLanguage.at("language")); - const nlohmann::json& translations = data["translations"]; - if (!translations.is_array() || translations.size() == 0) + const boost::json::value& translations = data.at("translations"); + if (!translations.is_array() || translations.as_array().size() == 0) { return false; } - const nlohmann::json& first = translations[0U]; - if (!first.is_object() || first.find("text") == first.end()) + const boost::json::value& first = translations.at(0U); + if (!first.is_object() || !first.as_object().contains("text")) { return false; } - translation = first["text"].get<std::string>(); + translation = boost::json::value_to<std::string>(first.at("text")); return true; } @@ -755,29 +745,26 @@ std::string LLAzureTranslationHandler::parseErrorResponse( // Expected: "{\"error\":{\"code\":400000,\"message\":\"One of the request inputs is not valid.\"}}" // But for now just verify response is a valid json with an error - nlohmann::json root; - try + boost::json::error_code ec; + boost::json::value root = boost::json::parse(body, ec); + if (ec.failed()) { - root = nlohmann::json::parse(body); - } - catch(const nlohmann::json::exception&) - { return std::string(); - } + } - if (!root.is_object() || root.find("error") == root.end()) + if (!root.is_object() || !root.as_object().contains("error")) { return std::string(); } - const nlohmann::json& error_map = root["error"]; + const boost::json::value& error_map = root.at("error"); - if (!error_map.is_object() || error_map.find("message") == error_map.end()) + if (!error_map.is_object() || !error_map.as_object().contains("message")) { return std::string(); } - return error_map["message"].get<std::string>(); + return boost::json::value_to<std::string>(error_map.at("message")); } // static @@ -984,41 +971,38 @@ bool LLDeepLTranslationHandler::parseResponse( //Example: // "{\"translations\":[{\"detected_source_language\":\"EN\",\"text\":\"test\"}]}" - nlohmann::json root; - try + boost::json::error_code ec; + boost::json::value root = boost::json::parse(body, ec); + if (ec.failed()) { - root = nlohmann::json::parse(body); - } - catch(nlohmann::json::exception &e) - { - err_msg = e.what(); + err_msg = ec.message(); return false; - } + } if (!root.is_object() - || root.find("translations") == root.end()) // empty response? should not happen + || !root.as_object().contains("translations")) // empty response? should not happen { return false; } // Request succeeded, extract translation from the response. - const nlohmann::json& translations = root["translations"]; - if (!translations.is_array() || translations.size() == 0) + const boost::json::value& translations = root.at("translations"); + if (!translations.is_array() || translations.as_array().size() == 0) { return false; } - const nlohmann::json& data= translations[0U]; + const boost::json::value& data= translations.at(0U); if (!data.is_object() - || data.find("detected_source_language") == data.end() - || data.find("text") == data.end()) + || !data.as_object().contains("detected_source_language") + || !data.as_object().contains("text")) { return false; } - detected_lang = data["detected_source_language"].get<std::string>(); + detected_lang = boost::json::value_to<std::string>(root.at("detected_source_language")); LLStringUtil::toLower(detected_lang); - translation = data["text"].get<std::string>(); + translation = boost::json::value_to<std::string>(root.at("text")); return true; } @@ -1034,22 +1018,19 @@ std::string LLDeepLTranslationHandler::parseErrorResponse( const std::string& body) { // Example: "{\"message\":\"One of the request inputs is not valid.\"}" - nlohmann::json root; - try - { - root = nlohmann::json::parse(body); - } - catch(const nlohmann::json::exception &) - { + boost::json::error_code ec; + boost::json::value root = boost::json::parse(body, ec); + if (ec.failed()) + { return {}; - } + } - if (!root.is_object() || root.find("message") == root.end()) + if (!root.is_object() || !root.as_object().contains("message")) { return std::string(); } - return root["message"].get<std::string>(); + return boost::json::value_to<std::string>(root.at("message")); } // static