summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java272
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt245
2 files changed, 245 insertions, 272 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java
deleted file mode 100644
index 2b3d257a3..000000000
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java
+++ /dev/null
@@ -1,272 +0,0 @@
-package org.yuzu.yuzu_emu.features.settings.utils;
-
-import androidx.annotation.NonNull;
-
-import org.yuzu.yuzu_emu.YuzuApplication;
-import org.yuzu.yuzu_emu.NativeLibrary;
-import org.yuzu.yuzu_emu.R;
-import org.yuzu.yuzu_emu.features.settings.model.FloatSetting;
-import org.yuzu.yuzu_emu.features.settings.model.IntSetting;
-import org.yuzu.yuzu_emu.features.settings.model.Setting;
-import org.yuzu.yuzu_emu.features.settings.model.SettingSection;
-import org.yuzu.yuzu_emu.features.settings.model.Settings;
-import org.yuzu.yuzu_emu.features.settings.model.StringSetting;
-import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivityView;
-import org.yuzu.yuzu_emu.utils.BiMap;
-import org.yuzu.yuzu_emu.utils.DirectoryInitialization;
-import org.yuzu.yuzu_emu.utils.Log;
-import org.ini4j.Wini;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-/**
- * Contains static methods for interacting with .ini files in which settings are stored.
- */
-public final class SettingsFile {
- public static final String FILE_NAME_CONFIG = "config";
-
- public static final String KEY_DESIGN = "design";
-
- // CPU
- public static final String KEY_CPU_ACCURACY = "cpu_accuracy";
- // System
- public static final String KEY_USE_DOCKED_MODE = "use_docked_mode";
- public static final String KEY_REGION_INDEX = "region_index";
- public static final String KEY_LANGUAGE_INDEX = "language_index";
- public static final String KEY_RENDERER_BACKEND = "backend";
- // Renderer
- public static final String KEY_RENDERER_RESOLUTION = "resolution_setup";
- public static final String KEY_RENDERER_ASPECT_RATIO = "aspect_ratio";
- public static final String KEY_RENDERER_ACCURACY = "gpu_accuracy";
- public static final String KEY_RENDERER_ASYNCHRONOUS_SHADERS = "use_asynchronous_shaders";
- public static final String KEY_RENDERER_FORCE_MAX_CLOCK = "force_max_clock";
- public static final String KEY_RENDERER_USE_SPEED_LIMIT = "use_speed_limit";
- public static final String KEY_RENDERER_DEBUG = "debug";
- public static final String KEY_RENDERER_SPEED_LIMIT = "speed_limit";
- // Audio
- public static final String KEY_AUDIO_VOLUME = "volume";
-
- private static BiMap<String, String> sectionsMap = new BiMap<>();
-
- static {
- //TODO: Add members to sectionsMap when game-specific settings are added
- }
-
-
- private SettingsFile() {
- }
-
- /**
- * Reads a given .ini file from disk and returns it as a HashMap of Settings, themselves
- * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it
- * failed.
- *
- * @param ini The ini file to load the settings from
- * @param isCustomGame
- * @param view The current view.
- * @return An Observable that emits a HashMap of the file's contents, then completes.
- */
- static HashMap<String, SettingSection> readFile(final File ini, boolean isCustomGame, SettingsActivityView view) {
- HashMap<String, SettingSection> sections = new Settings.SettingsSectionMap();
-
- BufferedReader reader = null;
-
- try {
- reader = new BufferedReader(new FileReader(ini));
-
- SettingSection current = null;
- for (String line; (line = reader.readLine()) != null; ) {
- if (line.startsWith("[") && line.endsWith("]")) {
- current = sectionFromLine(line, isCustomGame);
- sections.put(current.getName(), current);
- } else if ((current != null)) {
- Setting setting = settingFromLine(current, line);
- if (setting != null) {
- current.putSetting(setting);
- }
- }
- }
- } catch (FileNotFoundException e) {
- Log.error("[SettingsFile] File not found: " + e.getMessage());
- if (view != null)
- view.onSettingsFileNotFound();
- } catch (IOException e) {
- Log.error("[SettingsFile] Error reading from: " + e.getMessage());
- if (view != null)
- view.onSettingsFileNotFound();
- } finally {
- if (reader != null) {
- try {
- reader.close();
- } catch (IOException e) {
- Log.error("[SettingsFile] Error closing: " + e.getMessage());
- }
- }
- }
-
- return sections;
- }
-
- public static HashMap<String, SettingSection> readFile(final String fileName, SettingsActivityView view) {
- return readFile(getSettingsFile(fileName), false, view);
- }
-
- /**
- * Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves
- * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it
- * failed.
- *
- * @param gameId the id of the game to load it's settings.
- * @param view The current view.
- */
- public static HashMap<String, SettingSection> readCustomGameSettings(final String gameId, SettingsActivityView view) {
- return readFile(getCustomGameSettingsFile(gameId), true, view);
- }
-
- /**
- * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error
- * telling why it failed.
- *
- * @param fileName The target filename without a path or extension.
- * @param sections The HashMap containing the Settings we want to serialize.
- * @param view The current view.
- */
- public static void saveFile(final String fileName, TreeMap<String, SettingSection> sections,
- SettingsActivityView view) {
- File ini = getSettingsFile(fileName);
-
- try {
- Wini writer = new Wini(ini);
-
- Set<String> keySet = sections.keySet();
- for (String key : keySet) {
- SettingSection section = sections.get(key);
- writeSection(writer, section);
- }
- writer.store();
- } catch (IOException e) {
- Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
- view.showToastMessage(YuzuApplication.getAppContext().getString(R.string.error_saving, fileName, e.getMessage()), false);
- }
- }
-
-
- public static void saveCustomGameSettings(final String gameId, final HashMap<String, SettingSection> sections) {
- Set<String> sortedSections = new TreeSet<>(sections.keySet());
-
- for (String sectionKey : sortedSections) {
- SettingSection section = sections.get(sectionKey);
-
- HashMap<String, Setting> settings = section.getSettings();
- Set<String> sortedKeySet = new TreeSet<>(settings.keySet());
-
- for (String settingKey : sortedKeySet) {
- Setting setting = settings.get(settingKey);
- NativeLibrary.SetUserSetting(gameId, mapSectionNameFromIni(section.getName()), setting.getKey(), setting.getValueAsString());
- }
- }
- }
-
- private static String mapSectionNameFromIni(String generalSectionName) {
- if (sectionsMap.getForward(generalSectionName) != null) {
- return sectionsMap.getForward(generalSectionName);
- }
-
- return generalSectionName;
- }
-
- private static String mapSectionNameToIni(String generalSectionName) {
- if (sectionsMap.getBackward(generalSectionName) != null) {
- return sectionsMap.getBackward(generalSectionName);
- }
-
- return generalSectionName;
- }
-
- @NonNull
- private static File getSettingsFile(String fileName) {
- return new File(
- DirectoryInitialization.getUserDirectory() + "/config/" + fileName + ".ini");
- }
-
- private static File getCustomGameSettingsFile(String gameId) {
- return new File(DirectoryInitialization.getUserDirectory() + "/GameSettings/" + gameId + ".ini");
- }
-
- private static SettingSection sectionFromLine(String line, boolean isCustomGame) {
- String sectionName = line.substring(1, line.length() - 1);
- if (isCustomGame) {
- sectionName = mapSectionNameToIni(sectionName);
- }
- return new SettingSection(sectionName);
- }
-
- /**
- * For a line of text, determines what type of data is being represented, and returns
- * a Setting object containing this data.
- *
- * @param current The section currently being parsed by the consuming method.
- * @param line The line of text being parsed.
- * @return A typed Setting containing the key/value contained in the line.
- */
- private static Setting settingFromLine(SettingSection current, String line) {
- String[] splitLine = line.split("=");
-
- if (splitLine.length != 2) {
- Log.warning("Skipping invalid config line \"" + line + "\"");
- return null;
- }
-
- String key = splitLine[0].trim();
- String value = splitLine[1].trim();
-
- if (value.isEmpty()) {
- Log.warning("Skipping null value in config line \"" + line + "\"");
- return null;
- }
-
- try {
- int valueAsInt = Integer.parseInt(value);
-
- return new IntSetting(key, current.getName(), valueAsInt);
- } catch (NumberFormatException ex) {
- }
-
- try {
- float valueAsFloat = Float.parseFloat(value);
-
- return new FloatSetting(key, current.getName(), valueAsFloat);
- } catch (NumberFormatException ex) {
- }
-
- return new StringSetting(key, current.getName(), value);
- }
-
- /**
- * Writes the contents of a Section HashMap to disk.
- *
- * @param parser A Wini pointed at a file on disk.
- * @param section A section containing settings to be written to the file.
- */
- private static void writeSection(Wini parser, SettingSection section) {
- // Write the section header.
- String header = section.getName();
-
- // Write this section's values.
- HashMap<String, Setting> settings = section.getSettings();
- Set<String> keySet = settings.keySet();
-
- for (String key : keySet) {
- Setting setting = settings.get(key);
- parser.put(header, setting.getKey(), setting.getValueAsString());
- }
- }
-}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt
new file mode 100644
index 000000000..8e21c65f0
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt
@@ -0,0 +1,245 @@
+package org.yuzu.yuzu_emu.features.settings.utils
+
+import org.ini4j.Wini
+import org.yuzu.yuzu_emu.NativeLibrary
+import org.yuzu.yuzu_emu.R
+import org.yuzu.yuzu_emu.YuzuApplication
+import org.yuzu.yuzu_emu.features.settings.model.*
+import org.yuzu.yuzu_emu.features.settings.model.Settings.SettingsSectionMap
+import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivityView
+import org.yuzu.yuzu_emu.utils.BiMap
+import org.yuzu.yuzu_emu.utils.DirectoryInitialization
+import org.yuzu.yuzu_emu.utils.Log
+import java.io.*
+import java.util.*
+
+/**
+ * Contains static methods for interacting with .ini files in which settings are stored.
+ */
+object SettingsFile {
+ const val FILE_NAME_CONFIG = "config"
+ const val KEY_DESIGN = "design"
+
+ // CPU
+ const val KEY_CPU_ACCURACY = "cpu_accuracy"
+
+ // System
+ const val KEY_USE_DOCKED_MODE = "use_docked_mode"
+ const val KEY_REGION_INDEX = "region_index"
+ const val KEY_LANGUAGE_INDEX = "language_index"
+ const val KEY_RENDERER_BACKEND = "backend"
+
+ // Renderer
+ const val KEY_RENDERER_RESOLUTION = "resolution_setup"
+ const val KEY_RENDERER_ASPECT_RATIO = "aspect_ratio"
+ const val KEY_RENDERER_ACCURACY = "gpu_accuracy"
+ const val KEY_RENDERER_ASYNCHRONOUS_SHADERS = "use_asynchronous_shaders"
+ const val KEY_RENDERER_FORCE_MAX_CLOCK = "force_max_clock"
+ const val KEY_RENDERER_USE_SPEED_LIMIT = "use_speed_limit"
+ const val KEY_RENDERER_DEBUG = "debug"
+ const val KEY_RENDERER_SPEED_LIMIT = "speed_limit"
+
+ // Audio
+ const val KEY_AUDIO_VOLUME = "volume"
+ private val sectionsMap = BiMap<String?, String?>()
+
+ /**
+ * Reads a given .ini file from disk and returns it as a HashMap of Settings, themselves
+ * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it
+ * failed.
+ *
+ * @param ini The ini file to load the settings from
+ * @param isCustomGame
+ * @param view The current view.
+ * @return An Observable that emits a HashMap of the file's contents, then completes.
+ */
+ private fun readFile(
+ ini: File?,
+ isCustomGame: Boolean,
+ view: SettingsActivityView?
+ ): HashMap<String, SettingSection?> {
+ val sections: HashMap<String, SettingSection?> = SettingsSectionMap()
+ var reader: BufferedReader? = null
+ try {
+ reader = BufferedReader(FileReader(ini))
+ var current: SettingSection? = null
+ var line: String?
+ while (reader.readLine().also { line = it } != null) {
+ if (line!!.startsWith("[") && line!!.endsWith("]")) {
+ current = sectionFromLine(line!!, isCustomGame)
+ sections[current.name] = current
+ } else if (current != null) {
+ val setting = settingFromLine(current, line!!)
+ if (setting != null) {
+ current.putSetting(setting)
+ }
+ }
+ }
+ } catch (e: FileNotFoundException) {
+ Log.error("[SettingsFile] File not found: " + e.message)
+ view?.onSettingsFileNotFound()
+ } catch (e: IOException) {
+ Log.error("[SettingsFile] Error reading from: " + e.message)
+ view?.onSettingsFileNotFound()
+ } finally {
+ if (reader != null) {
+ try {
+ reader.close()
+ } catch (e: IOException) {
+ Log.error("[SettingsFile] Error closing: " + e.message)
+ }
+ }
+ }
+ return sections
+ }
+
+ fun readFile(fileName: String, view: SettingsActivityView): HashMap<String, SettingSection?> {
+ return readFile(getSettingsFile(fileName), false, view)
+ }
+
+ /**
+ * Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves
+ * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it
+ * failed.
+ *
+ * @param gameId the id of the game to load it's settings.
+ * @param view The current view.
+ */
+ fun readCustomGameSettings(
+ gameId: String,
+ view: SettingsActivityView
+ ): HashMap<String, SettingSection?> {
+ return readFile(getCustomGameSettingsFile(gameId), true, view)
+ }
+
+ /**
+ * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error
+ * telling why it failed.
+ *
+ * @param fileName The target filename without a path or extension.
+ * @param sections The HashMap containing the Settings we want to serialize.
+ * @param view The current view.
+ */
+ fun saveFile(
+ fileName: String,
+ sections: TreeMap<String, SettingSection>,
+ view: SettingsActivityView
+ ) {
+ val ini = getSettingsFile(fileName)
+ try {
+ val writer = Wini(ini)
+ val keySet: Set<String> = sections.keys
+ for (key in keySet) {
+ val section = sections[key]
+ writeSection(writer, section!!)
+ }
+ writer.store()
+ } catch (e: IOException) {
+ Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.message)
+ view.showToastMessage(
+ YuzuApplication.appContext
+ .getString(R.string.error_saving, fileName, e.message),
+ false
+ )
+ }
+ }
+
+ fun saveCustomGameSettings(gameId: String?, sections: HashMap<String, SettingSection?>) {
+ val sortedSections: Set<String> = TreeSet(sections.keys)
+ for (sectionKey in sortedSections) {
+ val section = sections[sectionKey]
+ val settings = section!!.settings
+ val sortedKeySet: Set<String> = TreeSet(settings.keys)
+ for (settingKey in sortedKeySet) {
+ val setting = settings[settingKey]
+ NativeLibrary.SetUserSetting(
+ gameId, mapSectionNameFromIni(
+ section.name
+ ), setting!!.key, setting.valueAsString
+ )
+ }
+ }
+ }
+
+ private fun mapSectionNameFromIni(generalSectionName: String): String? {
+ return if (sectionsMap.getForward(generalSectionName) != null) {
+ sectionsMap.getForward(generalSectionName)
+ } else generalSectionName
+ }
+
+ private fun mapSectionNameToIni(generalSectionName: String): String {
+ return if (sectionsMap.getBackward(generalSectionName) != null) {
+ sectionsMap.getBackward(generalSectionName).toString()
+ } else generalSectionName
+ }
+
+ private fun getSettingsFile(fileName: String): File {
+ return File(
+ DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini"
+ )
+ }
+
+ private fun getCustomGameSettingsFile(gameId: String): File {
+ return File(DirectoryInitialization.userDirectory + "/GameSettings/" + gameId + ".ini")
+ }
+
+ private fun sectionFromLine(line: String, isCustomGame: Boolean): SettingSection {
+ var sectionName: String = line.substring(1, line.length - 1)
+ if (isCustomGame) {
+ sectionName = mapSectionNameToIni(sectionName)
+ }
+ return SettingSection(sectionName)
+ }
+
+ /**
+ * For a line of text, determines what type of data is being represented, and returns
+ * a Setting object containing this data.
+ *
+ * @param current The section currently being parsed by the consuming method.
+ * @param line The line of text being parsed.
+ * @return A typed Setting containing the key/value contained in the line.
+ */
+ private fun settingFromLine(current: SettingSection, line: String): Setting? {
+ val splitLine = line.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
+ if (splitLine.size != 2) {
+ Log.warning("Skipping invalid config line \"$line\"")
+ return null
+ }
+ val key = splitLine[0].trim { it <= ' ' }
+ val value = splitLine[1].trim { it <= ' ' }
+ if (value.isEmpty()) {
+ Log.warning("Skipping null value in config line \"$line\"")
+ return null
+ }
+ try {
+ val valueAsInt = value.toInt()
+ return IntSetting(key, current.name, valueAsInt)
+ } catch (_: NumberFormatException) {
+ }
+ try {
+ val valueAsFloat = value.toFloat()
+ return FloatSetting(key, current.name, valueAsFloat)
+ } catch (_: NumberFormatException) {
+ }
+ return StringSetting(key, current.name, value)
+ }
+
+ /**
+ * Writes the contents of a Section HashMap to disk.
+ *
+ * @param parser A Wini pointed at a file on disk.
+ * @param section A section containing settings to be written to the file.
+ */
+ private fun writeSection(parser: Wini, section: SettingSection) {
+ // Write the section header.
+ val header = section.name
+
+ // Write this section's values.
+ val settings = section.settings
+ val keySet: Set<String> = settings.keys
+ for (key in keySet) {
+ val setting = settings[key]
+ parser.put(header, setting!!.key, setting.valueAsString)
+ }
+ }
+}