diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.kt
index 3f6a14480..925e17805 100644
--- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.kt
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.kt
@@ -48,7 +48,8 @@ enum class BooleanSetting(
DEBUG_RENDERER("renderer_debug", Settings.SECTION_DEBUG, false),
DISABLE_RIGHT_EYE_RENDER("disable_right_eye_render", Settings.SECTION_RENDERER, false),
USE_ARTIC_BASE_CONTROLLER("use_artic_base_controller", Settings.SECTION_CONTROLS, false),
- UPRIGHT_SCREEN("upright_screen", Settings.SECTION_LAYOUT, false);
+ UPRIGHT_SCREEN("upright_screen", Settings.SECTION_LAYOUT, false),
+ COMPRESS_INSTALLED_CIA_CONTENT("compress_cia_installs", Settings.SECTION_STORAGE, false);
override var boolean: Boolean = defaultValue
@@ -80,7 +81,8 @@ enum class BooleanSetting(
CPU_JIT,
ASYNC_CUSTOM_LOADING,
SHADERS_ACCURATE_MUL,
- USE_ARTIC_BASE_CONTROLLER
+ USE_ARTIC_BASE_CONTROLLER,
+ COMPRESS_INSTALLED_CIA_CONTENT,
)
fun from(key: String): BooleanSetting? =
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt
index b229ffe17..02d10cfe9 100644
--- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.kt
@@ -112,6 +112,7 @@ class Settings {
const val SECTION_CUSTOM_LANDSCAPE = "Custom Landscape Layout"
const val SECTION_CUSTOM_PORTRAIT = "Custom Portrait Layout"
const val SECTION_PERFORMANCE_OVERLAY = "Performance Overlay"
+ const val SECTION_STORAGE = "Storage"
const val KEY_BUTTON_A = "button_a"
const val KEY_BUTTON_B = "button_b"
@@ -237,6 +238,7 @@ class Settings {
SECTION_CONTROLS,
SECTION_RENDERER,
SECTION_LAYOUT,
+ SECTION_STORAGE,
SECTION_UTILITY,
SECTION_AUDIO,
SECTION_DEBUG
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt
index e6b67e448..378a2cc66 100644
--- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -565,6 +565,16 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
BooleanSetting.ALLOW_PLUGIN_LOADER.defaultValue
)
)
+ add(HeaderSetting(R.string.storage))
+ add(
+ SwitchSetting(
+ BooleanSetting.COMPRESS_INSTALLED_CIA_CONTENT,
+ R.string.compress_cia_installs,
+ R.string.compress_cia_installs_description,
+ BooleanSetting.COMPRESS_INSTALLED_CIA_CONTENT.key,
+ BooleanSetting.COMPRESS_INSTALLED_CIA_CONTENT.defaultValue
+ )
+ )
}
}
diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp
index b46333ada..d5c699924 100644
--- a/src/android/app/src/main/jni/config.cpp
+++ b/src/android/app/src/main/jni/config.cpp
@@ -218,6 +218,9 @@ void Config::ReadValues() {
ReadSetting("Layout", Settings::values.custom_portrait_bottom_width);
ReadSetting("Layout", Settings::values.custom_portrait_bottom_height);
+ // Storage
+ ReadSetting("Storage", Settings::values.compress_cia_installs);
+
// Utility
ReadSetting("Utility", Settings::values.dump_textures);
ReadSetting("Utility", Settings::values.custom_textures);
diff --git a/src/android/app/src/main/jni/default_ini.h b/src/android/app/src/main/jni/default_ini.h
index 83fa897fa..a34e4370e 100644
--- a/src/android/app/src/main/jni/default_ini.h
+++ b/src/android/app/src/main/jni/default_ini.h
@@ -210,6 +210,11 @@ disable_right_eye_render =
# 5: Custom Layout
layout_option =
+[Storage]
+# Whether to compress the installed CIA contents
+# 0 (default): Do not compress, 1: Compress
+compress_cia_installs =
+
# Position of the performance overlay
# 0: Top Left
# 1: Center Top
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 3d47200be..86950bf5c 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -214,6 +214,9 @@
Region Mismatch Warning
The country setting is not valid for the selected emulated region.
The country setting is not valid for the current linked console.
+ Storage
+ Compress installed CIA content
+ Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.
Inner Camera
diff --git a/src/citra_qt/citra_qt.cpp b/src/citra_qt/citra_qt.cpp
index 8fd54ba54..da988cc0f 100644
--- a/src/citra_qt/citra_qt.cpp
+++ b/src/citra_qt/citra_qt.cpp
@@ -3081,7 +3081,7 @@ void GMainWindow::OnCompressFile() {
compress_info.recommended_compressed_extension = "zcia";
compress_info.recommended_uncompressed_extension = "cia";
compress_info.underlying_magic = std::array({'C', 'I', 'A', '\0'});
- frame_size = FileUtil::Z3DSWriteIOFile::MAX_FRAME_SIZE;
+ frame_size = FileUtil::Z3DSWriteIOFile::DEFAULT_CIA_FRAME_SIZE;
}
}
}
diff --git a/src/citra_qt/configuration/configure_storage.ui b/src/citra_qt/configuration/configure_storage.ui
index 83d7ba123..1c8358dbc 100644
--- a/src/citra_qt/configuration/configure_storage.ui
+++ b/src/citra_qt/configuration/configure_storage.ui
@@ -184,10 +184,10 @@
-
- Compress installed CIA contents
+ Compress installed CIA content
- Enables compressing the contents of CIA files when they are installed to the emulated SD.
+ Compresses the content of CIA files when installed to the emulated SD card. Only affects CIA content which is installed while the setting is enabled.
diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp
index e3d5dac5f..694b11011 100644
--- a/src/common/zstd_compression.cpp
+++ b/src/common/zstd_compression.cpp
@@ -115,9 +115,13 @@ Z3DSMetadata::Z3DSMetadata(const std::span& source_data) {
while (!in.eof()) {
Item item;
ReadFromIStream(in, &item, sizeof(Item));
+ // If end item is reached, stop processing
+ if (item.type == Item::TYPE_END) {
+ break;
+ }
// Only binary type supported for now
if (item.type != Item::TYPE_BINARY) {
- break;
+ continue;
}
std::string name(item.name_len, '\0');
std::vector data(item.data_len);
@@ -145,6 +149,10 @@ std::vector Z3DSMetadata::AsBinary() {
WriteToOStream(out, it.second.data(), item.data_len);
}
+ // Write end item
+ Item end{};
+ WriteToOStream(out, &end, sizeof(end));
+
std::string out_str = out.str();
return std::vector(out_str.begin(), out_str.end());
}
diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h
index 03b9eb61e..590a40fcd 100644
--- a/src/common/zstd_compression.h
+++ b/src/common/zstd_compression.h
@@ -55,11 +55,12 @@ namespace FileUtil {
struct Z3DSFileHeader {
static constexpr std::array EXPECTED_MAGIC = {'Z', '3', 'D', 'S'};
- static constexpr u16 EXPECTED_VERSION = 1;
+ static constexpr u8 EXPECTED_VERSION = 1;
std::array magic = EXPECTED_MAGIC;
std::array underlying_magic{};
- u16 version = EXPECTED_VERSION;
+ u8 version = EXPECTED_VERSION;
+ u8 reserved = 0;
u16 header_size = 0;
u32 metadata_size = 0;
u64 compressed_size = 0;
@@ -70,6 +71,7 @@ struct Z3DSFileHeader {
ar & magic;
ar & underlying_magic;
ar & version;
+ ar & reserved;
ar & header_size;
ar & metadata_size;
ar & compressed_size;
@@ -126,8 +128,9 @@ private:
class Z3DSWriteIOFile : public IOFile {
public:
- static constexpr size_t DEFAULT_FRAME_SIZE = 256 * 1024; // 256KiB
- static constexpr size_t MAX_FRAME_SIZE = 0; // Let the lib decide, usually 1GiB
+ static constexpr size_t DEFAULT_FRAME_SIZE = 256 * 1024; // 256KiB
+ static constexpr size_t DEFAULT_CIA_FRAME_SIZE = 32 * 1024 * 1024; // 32MiB
+ static constexpr size_t MAX_FRAME_SIZE = 0; // Let the lib decide, usually 1GiB
Z3DSWriteIOFile();