diff --git a/launcher/Json.cpp b/launcher/Json.cpp index dd7287e00..688f9dae7 100644 --- a/launcher/Json.cpp +++ b/launcher/Json.cpp @@ -101,6 +101,21 @@ QJsonArray requireArray(const QJsonDocument& doc, const QString& what) return doc.array(); } +QJsonDocument parseUntilGarbage(const QByteArray& json, QJsonParseError* error, QString* garbage) +{ + auto doc = QJsonDocument::fromJson(json, error); + if (error->error == QJsonParseError::GarbageAtEnd) { + qsizetype offset = error->offset; + QByteArray validJson = json.left(offset); + doc = QJsonDocument::fromJson(validJson, error); + + if (garbage) + *garbage = json.right(json.size() - offset); + } + + return doc; +} + void writeString(QJsonObject& to, const QString& key, const QString& value) { if (!value.isEmpty()) { diff --git a/launcher/Json.h b/launcher/Json.h index 8a994d7bc..7a50af167 100644 --- a/launcher/Json.h +++ b/launcher/Json.h @@ -107,6 +107,9 @@ QJsonArray toJsonArray(const QList& container) ////////////////// READING //////////////////// +// Attempt to parse JSON up until garbage is encountered +QJsonDocument parseUntilGarbage(const QByteArray& json, QJsonParseError* error = nullptr, QString* garbage = nullptr); + /// @throw JsonException template T requireIsType(const QJsonValue& value, const QString& what = "Value"); diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp index 9b4bb4a50..60f836b4d 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp @@ -168,10 +168,15 @@ bool processZIP(DataPack* pack, ProcessingLevel level) // https://minecraft.wiki/w/Tutorials/Creating_a_resource_pack#Formatting_pack.mcmeta bool processMCMeta(DataPack* pack, QByteArray&& raw_data) { - try { - auto json_doc = QJsonDocument::fromJson(raw_data); - auto pack_obj = Json::requireObject(json_doc.object(), "pack", {}); + QJsonParseError parse_error; + auto json_doc = Json::parseUntilGarbage(raw_data, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Failed to parse JSON:" << parse_error.errorString(); + return false; + } + try { + auto pack_obj = Json::requireObject(json_doc.object(), "pack", {}); pack->setPackFormat(pack_obj["pack_format"].toInt()); pack->setDescription(DataPackUtils::processComponent(pack_obj.value("description"))); } catch (Json::JsonException& e) { diff --git a/launcher/ui/pages/instance/McClient.cpp b/launcher/ui/pages/instance/McClient.cpp index e42342a11..25c167122 100644 --- a/launcher/ui/pages/instance/McClient.cpp +++ b/launcher/ui/pages/instance/McClient.cpp @@ -81,16 +81,11 @@ void McClient::parseResponse() // 'resp' should now be the JSON string QJsonParseError parseError; - QJsonDocument doc = QJsonDocument::fromJson(m_resp, &parseError); + QJsonDocument doc = Json::parseUntilGarbage(m_resp, &parseError); if (parseError.error != QJsonParseError::NoError) { - QByteArray validJson = m_resp.left(parseError.offset); - doc = QJsonDocument::fromJson(validJson, &parseError); - - if (parseError.error != QJsonParseError::NoError) { - qDebug() << "Failed to parse JSON:" << parseError.errorString(); - emitFail(parseError.errorString()); - return; - } + qDebug() << "Failed to parse JSON:" << parseError.errorString(); + emitFail(parseError.errorString()); + return; } emitSucceed(doc.object()); }