Last active
July 14, 2021 19:28
-
-
Save Langerz82/05095b7431c4b7935416714ba9ce6bfe to your computer and use it in GitHub Desktop.
Compresses emulator gc for dolphin from ISO's to RVZ. Apply patch to dolphin emulator and build.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Source/Core/CMakeLists.txt b/Source/Core/CMakeLists.txt | |
index d176fcbf25..7fc17c9807 100644 | |
--- a/Source/Core/CMakeLists.txt | |
+++ b/Source/Core/CMakeLists.txt | |
@@ -7,6 +7,8 @@ add_subdirectory(UICommon) | |
add_subdirectory(VideoCommon) | |
add_subdirectory(VideoBackends) | |
+add_subdirectory(DolphinConvert) | |
+ | |
if(ENABLE_NOGUI) | |
add_subdirectory(DolphinNoGUI) | |
endif() | |
diff --git a/Source/Core/DolphinConvert/CMakeLists.txt b/Source/Core/DolphinConvert/CMakeLists.txt | |
new file mode 100644 | |
index 0000000000..5c8f27fa20 | |
--- /dev/null | |
+++ b/Source/Core/DolphinConvert/CMakeLists.txt | |
@@ -0,0 +1,18 @@ | |
+add_executable(dolphin-convert | |
+ ../DolphinNoGUI/Platform.cpp | |
+ ../DolphinNoGUI/Platform.h | |
+ ../DolphinNoGUI/PlatformHeadless.cpp | |
+ MainConvert.cpp | |
+) | |
+ | |
+set_target_properties(dolphin-convert PROPERTIES OUTPUT_NAME dolphin-emu-convert) | |
+ | |
+target_link_libraries(dolphin-convert | |
+PRIVATE | |
+ core | |
+ uicommon | |
+ cpp-optparse | |
+) | |
+ | |
+set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} dolphin-convert) | |
+install(TARGETS dolphin-convert RUNTIME DESTINATION ${bindir}) | |
diff --git a/Source/Core/DolphinConvert/MainConvert.cpp b/Source/Core/DolphinConvert/MainConvert.cpp | |
new file mode 100644 | |
index 0000000000..c1ad9ed067 | |
--- /dev/null | |
+++ b/Source/Core/DolphinConvert/MainConvert.cpp | |
@@ -0,0 +1,352 @@ | |
+// Copyright 2008 Dolphin Emulator Project | |
+// SPDX-License-Identifier: GPL-2.0-or-later | |
+ | |
+#include "DolphinNoGUI/Platform.h" | |
+ | |
+#include <OptionParser.h> | |
+#include <cstddef> | |
+#include <cstdio> | |
+#include <cstring> | |
+#include <signal.h> | |
+#include <string> | |
+#include <vector> | |
+#include <locale> | |
+ | |
+#include <algorithm> | |
+#include <functional> | |
+#include <future> | |
+#include <memory> | |
+#include <utility> | |
+ | |
+#ifndef _WIN32 | |
+#include <unistd.h> | |
+#else | |
+#include <Windows.h> | |
+#endif | |
+ | |
+#include "Common/StringUtil.h" | |
+#include "Core/Boot/Boot.h" | |
+#include "Core/BootManager.h" | |
+#include "Core/Core.h" | |
+#include "Core/DolphinAnalytics.h" | |
+#include "Core/Host.h" | |
+#include "DiscIO/WIABlob.h" | |
+ | |
+#include "UICommon/CommandLineParse.h" | |
+#ifdef USE_DISCORD_PRESENCE | |
+#include "UICommon/DiscordPresence.h" | |
+#endif | |
+#include "UICommon/UICommon.h" | |
+ | |
+static std::unique_ptr<Platform> s_platform; | |
+ | |
+static void signal_handler(int) | |
+{ | |
+ const char message[] = "A signal was received. A second signal will force Dolphin to stop.\n"; | |
+#ifdef _WIN32 | |
+ puts(message); | |
+#else | |
+ if (write(STDERR_FILENO, message, sizeof(message)) < 0) | |
+ { | |
+ } | |
+#endif | |
+ | |
+ s_platform->RequestShutdown(); | |
+} | |
+ | |
+std::vector<std::string> Host_GetPreferredLocales() | |
+{ | |
+ return {}; | |
+} | |
+ | |
+void Host_NotifyMapLoaded() | |
+{ | |
+} | |
+ | |
+void Host_RefreshDSPDebuggerWindow() | |
+{ | |
+} | |
+ | |
+bool Host_UIBlocksControllerState() | |
+{ | |
+ return false; | |
+} | |
+ | |
+static Common::Event s_update_main_frame_event; | |
+void Host_Message(HostMessageID id) | |
+{ | |
+ if (id == HostMessageID::WMUserStop) | |
+ s_platform->Stop(); | |
+} | |
+ | |
+void Host_UpdateTitle(const std::string& title) | |
+{ | |
+ s_platform->SetTitle(title); | |
+} | |
+ | |
+void Host_UpdateDisasmDialog() | |
+{ | |
+} | |
+ | |
+void Host_UpdateMainFrame() | |
+{ | |
+ s_update_main_frame_event.Set(); | |
+} | |
+ | |
+void Host_RequestRenderWindowSize(int width, int height) | |
+{ | |
+} | |
+ | |
+bool Host_RendererHasFocus() | |
+{ | |
+ return s_platform->IsWindowFocused(); | |
+} | |
+ | |
+bool Host_RendererHasFullFocus() | |
+{ | |
+ // Mouse capturing isn't implemented | |
+ return Host_RendererHasFocus(); | |
+} | |
+ | |
+bool Host_RendererIsFullscreen() | |
+{ | |
+ return s_platform->IsWindowFullscreen(); | |
+} | |
+ | |
+void Host_YieldToUI() | |
+{ | |
+} | |
+ | |
+void Host_TitleChanged() | |
+{ | |
+} | |
+ | |
+static std::unique_ptr<Platform> GetPlatform(const optparse::Values& options) | |
+{ | |
+ return Platform::CreateHeadlessPlatform(); | |
+} | |
+ | |
+ | |
+int main(int argc, char* argv[]) | |
+{ | |
+ auto parser = CommandLineParse::CreateParser(CommandLineParse::ParserOptions::OmitGUIOptions); | |
+ | |
+ parser->add_option("-p","--platform") | |
+ .type("string") | |
+ .help("type: [%choices]") | |
+ .choices({"GC","WII"}); | |
+ | |
+ parser->add_option("-c","--compress") | |
+ .type("string") | |
+ .help("compress: [%choices]") | |
+ .choices({"PURGE","BZIP2","ZSTD","LZMA","LZMA2","NONE"}); | |
+ | |
+ parser->add_option("-b","--blob") | |
+ .type("string") | |
+ .help("compress: [%choices]") | |
+ .choices({"GCZ","WIA","RVZ"}); | |
+ | |
+ parser->add_option("-s","--blocksize") | |
+ .type("int") | |
+ .help("memory blocksize (MB): 1 to 32."); | |
+ | |
+ parser->add_option("-l","--level") | |
+ .type("int") | |
+ .help("level: 0-9"); | |
+ | |
+ parser->add_option("-o","--output") | |
+ .type("string") | |
+ .help("output filename."); | |
+ | |
+ optparse::Values& options = CommandLineParse::ParseArguments(parser.get(), argc, argv); | |
+ std::vector<std::string> args = parser->args(); | |
+ | |
+ std::optional<std::string> save_state_path; | |
+ if (options.is_set("save_state")) | |
+ { | |
+ save_state_path = static_cast<const char*>(options.get("save_state")); | |
+ } | |
+ | |
+ std::string original_path; | |
+ std::unique_ptr<BootParameters> boot; | |
+ bool game_specified = false; | |
+ if (options.is_set("exec")) | |
+ { | |
+ const std::list<std::string> paths_list = options.all("exec"); | |
+ const std::vector<std::string> paths{std::make_move_iterator(std::begin(paths_list)), | |
+ std::make_move_iterator(std::end(paths_list))}; | |
+ boot = BootParameters::GenerateFromFile(paths, save_state_path); | |
+ game_specified = true; | |
+ } | |
+ else if (options.is_set("nand_title")) | |
+ { | |
+ const std::string hex_string = static_cast<const char*>(options.get("nand_title")); | |
+ if (hex_string.length() != 16) | |
+ { | |
+ fprintf(stderr, "Invalid title ID\n"); | |
+ parser->print_help(); | |
+ return 1; | |
+ } | |
+ const u64 title_id = std::stoull(hex_string, nullptr, 16); | |
+ boot = std::make_unique<BootParameters>(BootParameters::NANDTitle{title_id}); | |
+ } | |
+ else if (args.size()) | |
+ { | |
+ original_path = args.front(); | |
+ boot = BootParameters::GenerateFromFile(args.front(), save_state_path); | |
+ args.erase(args.begin()); | |
+ game_specified = true; | |
+ } | |
+ else | |
+ { | |
+ parser->print_help(); | |
+ return 0; | |
+ } | |
+ | |
+ std::string user_directory; | |
+ if (options.is_set("user")) | |
+ user_directory = static_cast<const char*>(options.get("user")); | |
+ | |
+ UICommon::SetUserDirectory(user_directory); | |
+ //UICommon::Init(); | |
+ | |
+ s_platform = GetPlatform(options); | |
+ if (!s_platform || !s_platform->Init()) | |
+ { | |
+ fprintf(stderr, "No platform found, or failed to initialize.\n"); | |
+ return 1; | |
+ } | |
+ | |
+ if (save_state_path && !game_specified) | |
+ { | |
+ fprintf(stderr, "A save state cannot be loaded without specifying a game to launch.\n"); | |
+ return 1; | |
+ } | |
+ | |
+ std::locale loc; | |
+ | |
+ DiscIO::Platform platform = DiscIO::Platform::GameCubeDisc; | |
+ if (options.is_set("platform")) | |
+ { | |
+ static std::unordered_map<std::string,DiscIO::Platform> const table = | |
+ { {"GC",DiscIO::Platform::GameCubeDisc}, {"WII", DiscIO::Platform::WiiDisc} }; | |
+ std::string tmp = std::toupper(static_cast<std::string>(options.get("platform")),loc); | |
+ auto it = table.find(tmp); | |
+ if (it != table.end()) { | |
+ platform = it->second; | |
+ } | |
+ } | |
+ | |
+ DiscIO::WIARVZCompressionType compression = DiscIO::WIARVZCompressionType::LZMA; | |
+ if (options.is_set("compress")) | |
+ { | |
+ static std::unordered_map<std::string,DiscIO::WIARVZCompressionType> const table = { | |
+ {"PURGE",DiscIO::WIARVZCompressionType::Purge}, | |
+ {"BZIP2",DiscIO::WIARVZCompressionType::Bzip2}, | |
+ {"ZSTD",DiscIO::WIARVZCompressionType::Zstd}, | |
+ {"LZMA",DiscIO::WIARVZCompressionType::LZMA}, | |
+ {"LZMA2",DiscIO::WIARVZCompressionType::LZMA2}, | |
+ {"NONE",DiscIO::WIARVZCompressionType::None}}; | |
+ std::string tmp = std::toupper(static_cast<std::string>(options.get("compress")),loc); | |
+ auto it = table.find(tmp); | |
+ if (it != table.end()) { | |
+ compression = it->second; | |
+ } | |
+ } | |
+ | |
+ int compression_level = 9; | |
+ if (options.is_set("level")) | |
+ { | |
+ compression_level = std::clamp(static_cast<int>(options.get("level")),0,9); | |
+ } | |
+ | |
+ std::string ext = "RVZ"; | |
+ DiscIO::BlobType choice = DiscIO::BlobType::RVZ; | |
+ if (options.is_set("blob")) | |
+ { | |
+ static std::unordered_map<std::string,DiscIO::BlobType> const table = { | |
+ {"GCZ",DiscIO::BlobType::GCZ}, | |
+ {"RVZ", DiscIO::BlobType::RVZ}, | |
+ {"WIA", DiscIO::BlobType::WIA}}; | |
+ std::string tmp = std::toupper(static_cast<std::string>(options.get("blob")),loc); | |
+ auto it = table.find(tmp); | |
+ if (it != table.end()) { | |
+ ext = it->first; | |
+ choice = it->second; | |
+ } | |
+ } | |
+ | |
+ size_t lastindex = original_path.find_last_of("."); | |
+ std::string dst_path = original_path.substr(0, lastindex) + | |
+ "." + ext; | |
+ if (options.is_set("output")) | |
+ { | |
+ dst_path = static_cast<std::string>(options.get("output")); | |
+ } | |
+ | |
+ constexpr int MAX_BLOCK_SIZE = 0x200000; | |
+ int block_size = MAX_BLOCK_SIZE; | |
+ if (options.is_set("size")) | |
+ { | |
+ block_size *= std::clamp(static_cast<int>(options.get("size")),1,32); | |
+ } | |
+ | |
+ std::unique_ptr<DiscIO::BlobReader> blob_reader = DiscIO::CreateBlobReader(original_path); | |
+ | |
+ std::cout << "input: " << original_path << std::endl; | |
+ std::cout << "output: " << dst_path << std::endl; | |
+ | |
+ const auto callback = [&](const std::string& text, float percent){ | |
+ return true; | |
+ }; | |
+ std::future<bool> success; | |
+ switch (choice) | |
+ { | |
+ case DiscIO::BlobType::GCZ: | |
+ success = std::async(std::launch::async, [&] { | |
+ const bool good = DiscIO::ConvertToGCZ( | |
+ blob_reader.get(), original_path, dst_path, | |
+ platform == DiscIO::Platform::WiiDisc ? 1 : 0, block_size, callback); | |
+ return good; | |
+ }); | |
+ break; | |
+ | |
+ case DiscIO::BlobType::WIA: | |
+ case DiscIO::BlobType::RVZ: | |
+ success = std::async(std::launch::async, [&] { | |
+ const bool good = | |
+ DiscIO::ConvertToWIAOrRVZ(blob_reader.get(), original_path, dst_path, | |
+ choice == DiscIO::BlobType::RVZ, compression, | |
+ compression_level, block_size, callback); | |
+ return good; | |
+ }); | |
+ break; | |
+ | |
+ default: | |
+ ASSERT(false); | |
+ break; | |
+ } | |
+ | |
+ | |
+#ifdef _WIN32 | |
+ signal(SIGINT, signal_handler); | |
+ signal(SIGTERM, signal_handler); | |
+#else | |
+ // Shut down cleanly on SIGINT and SIGTERM | |
+ struct sigaction sa; | |
+ sa.sa_handler = signal_handler; | |
+ sigemptyset(&sa.sa_mask); | |
+ sa.sa_flags = SA_RESETHAND; | |
+ sigaction(SIGINT, &sa, nullptr); | |
+ sigaction(SIGTERM, &sa, nullptr); | |
+#endif | |
+ | |
+ while (true) | |
+ { | |
+ if (success.get()) | |
+ { | |
+ std::cout << "done." << std::endl; | |
+ return 0; | |
+ } | |
+ } | |
+} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment