From 43fce3ae46ce94e0524e857f4805337bb000df1a Mon Sep 17 00:00:00 2001 From: Dylan Schooner Date: Thu, 18 Dec 2025 12:34:41 -0500 Subject: [PATCH 1/4] Trim unexpected info from pack.mcmeta Signed-off-by: Dylan Schooner --- .../mod/tasks/LocalDataPackParseTask.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp index 9b4bb4a50..97e441032 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp @@ -168,10 +168,20 @@ 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 = QJsonDocument::fromJson(raw_data, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + QByteArray validJson = raw_data.left(parse_error.offset); + json_doc = QJsonDocument::fromJson(validJson, &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) { From e1eee6e3caa282a3ef73db5ac2f37c852522d1dc Mon Sep 17 00:00:00 2001 From: Dylan Schooner Date: Thu, 18 Dec 2025 13:33:13 -0500 Subject: [PATCH 2/4] Add Json::parseUntilMalformed helper Signed-off-by: Dylan Schooner --- launcher/Json.cpp | 11 +++++++++++ launcher/Json.h | 3 +++ .../minecraft/mod/tasks/LocalDataPackParseTask.cpp | 10 ++-------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/launcher/Json.cpp b/launcher/Json.cpp index dd7287e00..7c6d82325 100644 --- a/launcher/Json.cpp +++ b/launcher/Json.cpp @@ -101,6 +101,17 @@ QJsonArray requireArray(const QJsonDocument& doc, const QString& what) return doc.array(); } +QJsonDocument parseUntilMalformed(const QByteArray& json, QJsonParseError* error) +{ + auto doc = QJsonDocument::fromJson(json, error); + if (error->error != QJsonParseError::NoError) { + QByteArray validJson = json.left(error->offset); + doc = QJsonDocument::fromJson(validJson, error); + } + + 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..35a5b655b 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 unexpected data is encountered +QJsonDocument parseUntilMalformed(const QByteArray& json, QJsonParseError* error = 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 97e441032..81c561f27 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp @@ -169,15 +169,9 @@ bool processZIP(DataPack* pack, ProcessingLevel level) bool processMCMeta(DataPack* pack, QByteArray&& raw_data) { QJsonParseError parse_error; - auto json_doc = QJsonDocument::fromJson(raw_data, &parse_error); + auto json_doc = Json::parseUntilMalformed(raw_data, &parse_error); if (parse_error.error != QJsonParseError::NoError) { - QByteArray validJson = raw_data.left(parse_error.offset); - json_doc = QJsonDocument::fromJson(validJson, &parse_error); - - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Failed to parse JSON:" << parse_error.errorString(); - return false; - } + qWarning() << "Failed to parse JSON:" << parse_error.errorString(); } try { From 9c7fe72f9cf282836915886827961537b8af4689 Mon Sep 17 00:00:00 2001 From: Dylan Schooner Date: Thu, 18 Dec 2025 14:14:29 -0500 Subject: [PATCH 3/4] Use Json::parseUntilMalformed in McClient::parseResponse Signed-off-by: Dylan Schooner --- .../minecraft/mod/tasks/LocalDataPackParseTask.cpp | 1 + launcher/ui/pages/instance/McClient.cpp | 13 ++++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp index 81c561f27..345db807b 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp @@ -172,6 +172,7 @@ bool processMCMeta(DataPack* pack, QByteArray&& raw_data) auto json_doc = Json::parseUntilMalformed(raw_data, &parse_error); if (parse_error.error != QJsonParseError::NoError) { qWarning() << "Failed to parse JSON:" << parse_error.errorString(); + return false; } try { diff --git a/launcher/ui/pages/instance/McClient.cpp b/launcher/ui/pages/instance/McClient.cpp index e42342a11..f91194dfe 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::parseUntilMalformed(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()); } From 51b47050f92123ed01c04dd99af1e619e25b261a Mon Sep 17 00:00:00 2001 From: Dylan Schooner Date: Thu, 18 Dec 2025 15:23:48 -0500 Subject: [PATCH 4/4] Check specifically for GarbageAtEnd error - Out parameter for garbage data\n- Rename parseUntilMalformed to parseUntilGarbage Signed-off-by: Dylan Schooner --- launcher/Json.cpp | 10 +++++++--- launcher/Json.h | 4 ++-- .../minecraft/mod/tasks/LocalDataPackParseTask.cpp | 2 +- launcher/ui/pages/instance/McClient.cpp | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/launcher/Json.cpp b/launcher/Json.cpp index 7c6d82325..688f9dae7 100644 --- a/launcher/Json.cpp +++ b/launcher/Json.cpp @@ -101,12 +101,16 @@ QJsonArray requireArray(const QJsonDocument& doc, const QString& what) return doc.array(); } -QJsonDocument parseUntilMalformed(const QByteArray& json, QJsonParseError* error) +QJsonDocument parseUntilGarbage(const QByteArray& json, QJsonParseError* error, QString* garbage) { auto doc = QJsonDocument::fromJson(json, error); - if (error->error != QJsonParseError::NoError) { - QByteArray validJson = json.left(error->offset); + 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; diff --git a/launcher/Json.h b/launcher/Json.h index 35a5b655b..7a50af167 100644 --- a/launcher/Json.h +++ b/launcher/Json.h @@ -107,8 +107,8 @@ QJsonArray toJsonArray(const QList& container) ////////////////// READING //////////////////// -// Attempt to parse JSON up until unexpected data is encountered -QJsonDocument parseUntilMalformed(const QByteArray& json, QJsonParseError* error = nullptr); +// Attempt to parse JSON up until garbage is encountered +QJsonDocument parseUntilGarbage(const QByteArray& json, QJsonParseError* error = nullptr, QString* garbage = nullptr); /// @throw JsonException template diff --git a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp index 345db807b..60f836b4d 100644 --- a/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalDataPackParseTask.cpp @@ -169,7 +169,7 @@ bool processZIP(DataPack* pack, ProcessingLevel level) bool processMCMeta(DataPack* pack, QByteArray&& raw_data) { QJsonParseError parse_error; - auto json_doc = Json::parseUntilMalformed(raw_data, &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; diff --git a/launcher/ui/pages/instance/McClient.cpp b/launcher/ui/pages/instance/McClient.cpp index f91194dfe..25c167122 100644 --- a/launcher/ui/pages/instance/McClient.cpp +++ b/launcher/ui/pages/instance/McClient.cpp @@ -81,7 +81,7 @@ void McClient::parseResponse() // 'resp' should now be the JSON string QJsonParseError parseError; - QJsonDocument doc = Json::parseUntilMalformed(m_resp, &parseError); + QJsonDocument doc = Json::parseUntilGarbage(m_resp, &parseError); if (parseError.error != QJsonParseError::NoError) { qDebug() << "Failed to parse JSON:" << parseError.errorString(); emitFail(parseError.errorString());