// SPDX-FileCopyrightText: 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> // // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3. * * 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "LocalWorldSaveParseTask.h" #include "FileSystem.h" #include #include #include #include #include namespace WorldSaveUtils { bool process(WorldSave& pack, ProcessingLevel level) { switch (pack.type()) { case ResourceType::FOLDER: return WorldSaveUtils::processFolder(pack, level); case ResourceType::ZIPFILE: return WorldSaveUtils::processZIP(pack, level); default: qWarning() << "Invalid type for world save parse task!"; return false; } } /// @brief checks a folder structure to see if it contains a level.dat /// @param dir the path to check /// @param saves used in recursive call if a "saves" dir was found /// @return std::tuple of ( /// bool , /// QString , /// bool /// ) static std::tuple contains_level_dat(QDir dir, bool saves = false) { for (auto const& entry : dir.entryInfoList()) { if (!entry.isDir()) { continue; } if (!saves && entry.fileName() == "saves") { return contains_level_dat(QDir(entry.filePath()), true); } QFileInfo level_dat(FS::PathCombine(entry.filePath(), "level.dat")); if (level_dat.exists() && level_dat.isFile()) { return std::make_tuple(true, entry.fileName(), saves); } } return std::make_tuple(false, "", saves); } bool processFolder(WorldSave& save, ProcessingLevel level) { Q_ASSERT(save.type() == ResourceType::FOLDER); auto [found, save_dir_name, found_saves_dir] = contains_level_dat(QDir(save.fileinfo().filePath())); if (!found) { return false; } save.setSaveDirName(save_dir_name); if (found_saves_dir) { save.setSaveFormat(WorldSaveFormat::MULTI); } else { save.setSaveFormat(WorldSaveFormat::SINGLE); } if (level == ProcessingLevel::BasicInfoOnly) { return true; // only need basic info already checked } // reserved for more intensive processing return true; // all tests passed } /// @brief checks a folder structure to see if it contains a level.dat /// @param zip the zip file to check /// @return std::tuple of ( /// bool , /// QString , /// bool /// ) static std::tuple contains_level_dat(QuaZip& zip) { bool saves = false; QuaZipDir zipDir(&zip); if (zipDir.exists("/saves")) { saves = true; zipDir.cd("/saves"); } for (auto const& entry : zipDir.entryList()) { zipDir.cd(entry); if (zipDir.exists("level.dat")) { return std::make_tuple(true, entry, saves); } zipDir.cd(".."); } return std::make_tuple(false, "", saves); } bool processZIP(WorldSave& save, ProcessingLevel level) { Q_ASSERT(save.type() == ResourceType::ZIPFILE); QuaZip zip(save.fileinfo().filePath()); if (!zip.open(QuaZip::mdUnzip)) return false; // can't open zip file auto [found, save_dir_name, found_saves_dir] = contains_level_dat(zip); if (save_dir_name.endsWith("/")) { save_dir_name.chop(1); } if (!found) { return false; } save.setSaveDirName(save_dir_name); if (found_saves_dir) { save.setSaveFormat(WorldSaveFormat::MULTI); } else { save.setSaveFormat(WorldSaveFormat::SINGLE); } if (level == ProcessingLevel::BasicInfoOnly) { zip.close(); return true; // only need basic info already checked } // reserved for more intensive processing zip.close(); return true; } bool validate(QFileInfo file) { WorldSave sp{ file }; return WorldSaveUtils::process(sp, ProcessingLevel::BasicInfoOnly) && sp.valid(); } } // namespace WorldSaveUtils LocalWorldSaveParseTask::LocalWorldSaveParseTask(int token, WorldSave& save) : Task(nullptr, false), m_token(token), m_save(save) {} bool LocalWorldSaveParseTask::abort() { m_aborted = true; return true; } void LocalWorldSaveParseTask::executeTask() { if (!WorldSaveUtils::process(m_save)) return; if (m_aborted) emitAborted(); else emitSucceeded(); }