Skip to content

Instantly share code, notes, and snippets.

@Langerz82
Last active July 14, 2021 19:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Langerz82/05095b7431c4b7935416714ba9ce6bfe to your computer and use it in GitHub Desktop.
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.
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