diff --git a/Source/Android/app/src/main/AndroidManifest.xml b/Source/Android/app/src/main/AndroidManifest.xml
index 7298c10137..56d6eadfbf 100644
--- a/Source/Android/app/src/main/AndroidManifest.xml
+++ b/Source/Android/app/src/main/AndroidManifest.xml
@@ -96,6 +96,10 @@
+
+
mCallbacks = new ArrayList<>();
+
+ @Override
+ public void onItemSelected(AdapterView> adapterView, View view, int position, long id)
+ {
+ if (mCurrentPosition != position)
+ setPosition(position);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> adapterView)
+ {
+ mCurrentPosition = -1;
+ }
+
+ int getPosition()
+ {
+ return mCurrentPosition;
+ }
+
+ void setPosition(int position)
+ {
+ mCurrentPosition = position;
+ for (Runnable callback : mCallbacks)
+ callback.run();
+ }
+
+ void populate(int valuesId)
+ {
+ mValuesId = valuesId;
+ }
+
+ boolean hasValues()
+ {
+ return mValuesId != -1;
+ }
+
+ int getValue(Context context)
+ {
+ return context.getResources().getIntArray(mValuesId)[mCurrentPosition];
+ }
+
+ int getValueOr(Context context, int defaultValue)
+ {
+ return hasValues() ? getValue(context) : defaultValue;
+ }
+
+ void addCallback(Runnable callback)
+ {
+ mCallbacks.add(callback);
+ }
+ }
+
+ private static final String ARG_GAME_PATH = "game_path";
+
+ private static final String KEY_FORMAT = "convert_format";
+ private static final String KEY_BLOCK_SIZE = "convert_block_size";
+ private static final String KEY_COMPRESSION = "convert_compression";
+ private static final String KEY_COMPRESSION_LEVEL = "convert_compression_level";
+ private static final String KEY_REMOVE_JUNK_DATA = "remove_junk_data";
+
+ private static final int BLOB_TYPE_PLAIN = 0;
+ private static final int BLOB_TYPE_GCZ = 3;
+ private static final int BLOB_TYPE_WIA = 7;
+ private static final int BLOB_TYPE_RVZ = 8;
+
+ private static final int COMPRESSION_NONE = 0;
+ private static final int COMPRESSION_PURGE = 1;
+ private static final int COMPRESSION_BZIP2 = 2;
+ private static final int COMPRESSION_LZMA = 3;
+ private static final int COMPRESSION_LZMA2 = 4;
+ private static final int COMPRESSION_ZSTD = 5;
+
+ private SpinnerValue mFormat = new SpinnerValue();
+ private SpinnerValue mBlockSize = new SpinnerValue();
+ private SpinnerValue mCompression = new SpinnerValue();
+ private SpinnerValue mCompressionLevel = new SpinnerValue();
+
+ private GameFile gameFile;
+
+ public static ConvertFragment newInstance(String gamePath)
+ {
+ Bundle args = new Bundle();
+ args.putString(ARG_GAME_PATH, gamePath);
+
+ ConvertFragment fragment = new ConvertFragment();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ gameFile = GameFileCacheService.addOrGet(requireArguments().getString(ARG_GAME_PATH));
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState)
+ {
+ return inflater.inflate(R.layout.fragment_convert, container, false);
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, Bundle savedInstanceState)
+ {
+ populateFormats();
+ populateBlockSize();
+ populateCompression();
+ populateCompressionLevel();
+ populateRemoveJunkData();
+
+ mFormat.addCallback(this::populateBlockSize);
+ mFormat.addCallback(this::populateCompression);
+ mCompression.addCallback(this::populateCompressionLevel);
+ mFormat.addCallback(this::populateRemoveJunkData);
+
+ view.findViewById(R.id.button_convert).setOnClickListener(this);
+
+ if (savedInstanceState != null)
+ {
+ setSpinnerSelection(R.id.spinner_format, mFormat, savedInstanceState.getInt(KEY_FORMAT));
+ setSpinnerSelection(R.id.spinner_block_size, mBlockSize,
+ savedInstanceState.getInt(KEY_BLOCK_SIZE));
+ setSpinnerSelection(R.id.spinner_compression, mCompression,
+ savedInstanceState.getInt(KEY_COMPRESSION));
+ setSpinnerSelection(R.id.spinner_compression_level, mCompressionLevel,
+ savedInstanceState.getInt(KEY_COMPRESSION_LEVEL));
+
+ CheckBox removeJunkData = requireView().findViewById(R.id.checkbox_remove_junk_data);
+ removeJunkData.setChecked(savedInstanceState.getBoolean(KEY_REMOVE_JUNK_DATA));
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState)
+ {
+ outState.putInt(KEY_FORMAT, mFormat.getPosition());
+ outState.putInt(KEY_BLOCK_SIZE, mBlockSize.getPosition());
+ outState.putInt(KEY_COMPRESSION, mCompression.getPosition());
+ outState.putInt(KEY_COMPRESSION_LEVEL, mCompressionLevel.getPosition());
+
+ CheckBox removeJunkData = requireView().findViewById(R.id.checkbox_remove_junk_data);
+ outState.putBoolean(KEY_REMOVE_JUNK_DATA, removeJunkData.isChecked());
+ }
+
+ private void setSpinnerSelection(int id, SpinnerValue valueWrapper, int i)
+ {
+ ((Spinner) requireView().findViewById(id)).setSelection(i);
+ valueWrapper.setPosition(i);
+ }
+
+ private Spinner populateSpinner(int spinnerId, int entriesId, int valuesId,
+ SpinnerValue valueWrapper)
+ {
+ Spinner spinner = requireView().findViewById(spinnerId);
+
+ ArrayAdapter adapter = ArrayAdapter.createFromResource(requireContext(),
+ entriesId, android.R.layout.simple_spinner_item);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(adapter);
+
+ spinner.setEnabled(spinner.getCount() > 1);
+
+ valueWrapper.populate(valuesId);
+ valueWrapper.setPosition(spinner.getSelectedItemPosition());
+ spinner.setOnItemSelectedListener(valueWrapper);
+
+ return spinner;
+ }
+
+ private Spinner clearSpinner(int spinnerId, SpinnerValue valueWrapper)
+ {
+ Spinner spinner = requireView().findViewById(spinnerId);
+
+ spinner.setAdapter(null);
+
+ spinner.setEnabled(false);
+
+ valueWrapper.populate(-1);
+ valueWrapper.setPosition(-1);
+ spinner.setOnItemSelectedListener(valueWrapper);
+
+ return spinner;
+ }
+
+ private void populateFormats()
+ {
+ Spinner spinner = populateSpinner(R.id.spinner_format, R.array.convertFormatEntries,
+ R.array.convertFormatValues, mFormat);
+
+ if (gameFile.getBlobType() == BLOB_TYPE_PLAIN)
+ spinner.setSelection(spinner.getCount() - 1);
+ }
+
+ private void populateBlockSize()
+ {
+ switch (mFormat.getValue(requireContext()))
+ {
+ case BLOB_TYPE_GCZ:
+ // In the equivalent DolphinQt code, we have some logic for avoiding block sizes that can
+ // trigger bugs in Dolphin versions older than 5.0-11893, but it was too annoying to port.
+ // TODO: Port it?
+ populateSpinner(R.id.spinner_block_size, R.array.convertBlockSizeGczEntries,
+ R.array.convertBlockSizeGczValues, mBlockSize);
+ break;
+ case BLOB_TYPE_WIA:
+ populateSpinner(R.id.spinner_block_size, R.array.convertBlockSizeWiaEntries,
+ R.array.convertBlockSizeWiaValues, mBlockSize);
+ break;
+ case BLOB_TYPE_RVZ:
+ populateSpinner(R.id.spinner_block_size, R.array.convertBlockSizeRvzEntries,
+ R.array.convertBlockSizeRvzValues, mBlockSize).setSelection(2);
+ break;
+ default:
+ clearSpinner(R.id.spinner_block_size, mBlockSize);
+ }
+ }
+
+ private void populateCompression()
+ {
+ switch (mFormat.getValue(requireContext()))
+ {
+ case BLOB_TYPE_GCZ:
+ populateSpinner(R.id.spinner_compression, R.array.convertCompressionGczEntries,
+ R.array.convertCompressionGczValues, mCompression);
+ break;
+ case BLOB_TYPE_WIA:
+ populateSpinner(R.id.spinner_compression, R.array.convertCompressionWiaEntries,
+ R.array.convertCompressionWiaValues, mCompression);
+ break;
+ case BLOB_TYPE_RVZ:
+ populateSpinner(R.id.spinner_compression, R.array.convertCompressionRvzEntries,
+ R.array.convertCompressionRvzValues, mCompression).setSelection(4);
+ break;
+ default:
+ clearSpinner(R.id.spinner_compression, mCompression);
+ }
+ }
+
+ private void populateCompressionLevel()
+ {
+ switch (mCompression.getValueOr(requireContext(), COMPRESSION_NONE))
+ {
+ case COMPRESSION_BZIP2:
+ case COMPRESSION_LZMA:
+ case COMPRESSION_LZMA2:
+ populateSpinner(R.id.spinner_compression_level, R.array.convertCompressionLevelEntries,
+ R.array.convertCompressionLevelValues, mCompressionLevel).setSelection(4);
+ break;
+ case COMPRESSION_ZSTD:
+ // TODO: Query DiscIO for the supported compression levels, like we do in DolphinQt?
+ populateSpinner(R.id.spinner_compression_level, R.array.convertCompressionLevelZstdEntries,
+ R.array.convertCompressionLevelZstdValues, mCompressionLevel).setSelection(4);
+ break;
+ default:
+ clearSpinner(R.id.spinner_compression_level, mCompressionLevel);
+ }
+ }
+
+ private void populateRemoveJunkData()
+ {
+ boolean scrubbingAllowed = mFormat.getValue(requireContext()) != BLOB_TYPE_RVZ &&
+ !gameFile.isDatelDisc();
+
+ CheckBox removeJunkData = requireView().findViewById(R.id.checkbox_remove_junk_data);
+ removeJunkData.setEnabled(scrubbingAllowed);
+ if (!scrubbingAllowed)
+ removeJunkData.setChecked(false);
+ }
+
+ private boolean getRemoveJunkData()
+ {
+ CheckBox checkBoxScrub = requireView().findViewById(R.id.checkbox_remove_junk_data);
+ return checkBoxScrub.isChecked();
+ }
+
+ @Override
+ public void onClick(View view)
+ {
+ Context context = requireContext();
+
+ boolean scrub = getRemoveJunkData();
+ int format = mFormat.getValue(context);
+
+ boolean iso_warning = scrub && format == BLOB_TYPE_PLAIN;
+ boolean gcz_warning = !scrub && format == BLOB_TYPE_GCZ && !gameFile.isDatelDisc() &&
+ gameFile.getPlatform() == Platform.WII.toInt();
+
+ if (iso_warning || gcz_warning)
+ {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.DolphinDialogBase);
+ builder.setMessage(iso_warning ? R.string.convert_warning_iso : R.string.convert_warning_gcz)
+ .setPositiveButton(R.string.yes, (dialog, i) ->
+ {
+ dialog.dismiss();
+ convert();
+ })
+ .setNegativeButton(R.string.no, (dialog, i) -> dialog.dismiss());
+ AlertDialog alert = builder.create();
+ alert.show();
+ }
+ else
+ {
+ convert();
+ }
+ }
+
+ private void convert()
+ {
+ Context context = requireContext();
+
+ // TODO: Let the user select a path
+ String outPath = gameFile.getPath() + ".converted";
+
+ boolean success = NativeLibrary.ConvertDiscImage(gameFile.getPath(), outPath,
+ gameFile.getPlatform(), mFormat.getValue(context), mBlockSize.getValueOr(context,0),
+ mCompression.getValueOr(context,0), mCompressionLevel.getValueOr(context,0),
+ getRemoveJunkData());
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.DolphinDialogBase);
+ if (success)
+ {
+ builder.setMessage(R.string.convert_success_message)
+ .setCancelable(false)
+ .setPositiveButton(R.string.ok, (dialog, i) ->
+ {
+ dialog.dismiss();
+ requireActivity().finish();
+ });
+ }
+ else
+ {
+ builder.setMessage(R.string.convert_failure_message)
+ .setPositiveButton(R.string.ok, (dialog, i) -> dialog.dismiss());
+ }
+ AlertDialog alert = builder.create();
+ alert.show();
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.java
index dd1dd2898e..c0b55f5da7 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/GameFile.java
@@ -38,6 +38,8 @@ public class GameFile
public native int getRevision();
+ public native int getBlobType();
+
public native String getBlobTypeString();
public native long getBlockSize();
@@ -48,6 +50,8 @@ public class GameFile
public native long getFileSize();
+ public native boolean isDatelDisc();
+
public native int[] getBanner();
public native int getBannerWidth();
diff --git a/Source/Android/app/src/main/res/layout-w680dp-land/activity_convert.xml b/Source/Android/app/src/main/res/layout-w680dp-land/activity_convert.xml
new file mode 100644
index 0000000000..bd37c3deb6
--- /dev/null
+++ b/Source/Android/app/src/main/res/layout-w680dp-land/activity_convert.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/Android/app/src/main/res/layout/activity_convert.xml b/Source/Android/app/src/main/res/layout/activity_convert.xml
new file mode 100644
index 0000000000..b63559e248
--- /dev/null
+++ b/Source/Android/app/src/main/res/layout/activity_convert.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/Android/app/src/main/res/layout/fragment_convert.xml b/Source/Android/app/src/main/res/layout/fragment_convert.xml
new file mode 100644
index 0000000000..938c3239a5
--- /dev/null
+++ b/Source/Android/app/src/main/res/layout/fragment_convert.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Source/Android/app/src/main/res/values/arrays.xml b/Source/Android/app/src/main/res/values/arrays.xml
index 5adc40229d..724ac6d8c4 100644
--- a/Source/Android/app/src/main/res/values/arrays.xml
+++ b/Source/Android/app/src/main/res/values/arrays.xml
@@ -387,6 +387,7 @@
- Details
+ - Convert File
- Set as Default ISO
- Core Settings
- GFX Settings
@@ -395,6 +396,7 @@
- Details
+ - Convert File
- Set as Default ISO
- Core Settings
- GFX Settings
@@ -419,4 +421,147 @@
- Use Device Sensors (Without Pointer Emulation)
- Don\'t Use Device Sensors
+
+
+ - ISO
+ - GCZ
+ - WIA
+ - RVZ
+
+
+ - 0
+ - 3
+ - 7
+ - 8
+
+
+
+ - 32 KiB
+
+
+ - 32768
+
+
+
+ - 2 MiB
+
+
+ - 2097152
+
+
+
+ - 32 KiB
+ - 64 KiB
+ - 128 KiB
+ - 256 KiB
+ - 512 KiB
+ - 1 MiB
+ - 2 MiB
+
+
+ - 32768
+ - 65536
+ - 131072
+ - 262144
+ - 524288
+ - 1048576
+ - 2097152
+
+
+
+ - Deflate
+
+
+ - 0
+
+
+
+ - No Compression
+ - Purge
+ - bzip2 (slow)
+ - LZMA (slow)
+ - LZMA2 (slow)
+
+
+ - 0
+ - 1
+ - 2
+ - 3
+ - 4
+
+
+
+ - No Compression
+ - bzip2 (slow)
+ - LZMA (slow)
+ - LZMA2 (slow)
+ - Zstandard (recommended)
+
+
+ - 0
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+
+
+
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+
+
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+
+
+
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+ - 10
+ - 11
+ - 12
+ - 13
+ - 14
+ - 15
+ - 16
+ - 17
+ - 18
+ - 19
+ - 20
+ - 21
+ - 22
+
+
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 8
+ - 9
+
diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml
index 7ced055909..977bd56bd4 100644
--- a/Source/Android/app/src/main/res/values/strings.xml
+++ b/Source/Android/app/src/main/res/values/strings.xml
@@ -330,6 +330,29 @@
Block Size
No Compression
+
+ Format
+ Block Size
+ Compression
+ Compression Level
+ Remove Junk Data (Irreversible)
+ Convert
+ Removing junk data does not save any space when converting to ISO (unless you package the ISO file in a compressed file format such as ZIP afterwards). Do you want to continue anyway?
+ Converting Wii disc images to GCZ without removing junk data does not save any noticeable amount of space compared to converting to ISO. Do you want to continue anyway?
+ The disc image was successfully converted.
+ Dolphin failed to complete the requested action.
+
+ISO: A simple and robust format which is supported by many programs. It takes up more space
+than any other format.
+\n\nGCZ: A basic compressed format which is compatible with most versions of Dolphin and some
+other programs. It can\'t efficiently compress junk data (unless removed) or encrypted Wii data.
+\n\nWIA: An advanced compressed format which is compatible with Dolphin 5.0-12188 and later,
+and a few other programs. It can efficiently compress encrypted Wii data, but not junk data
+(unless removed).
+\n\nRVZ: An advanced compressed format which is compatible with Dolphin 5.0-12188 and later.
+It can efficiently compress both junk data and encrypted Wii data.
+
+
Pause Emulation
Unpause Emulation
diff --git a/Source/Android/jni/GameList/GameFile.cpp b/Source/Android/jni/GameList/GameFile.cpp
index 741cf39b4f..31c95fc48d 100644
--- a/Source/Android/jni/GameList/GameFile.cpp
+++ b/Source/Android/jni/GameList/GameFile.cpp
@@ -63,6 +63,8 @@ JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getDiscNumb
jobject obj);
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getRevision(JNIEnv* env,
jobject obj);
+JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBlobType(JNIEnv* env,
+ jobject obj);
JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_model_GameFile_getBlobTypeString(JNIEnv* env, jobject obj);
JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBlockSize(JNIEnv* env,
@@ -73,6 +75,8 @@ JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_model_GameFile_shouldShowFileFormatDetails(JNIEnv* env, jobject obj);
JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getFileSize(JNIEnv* env,
jobject obj);
+JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_isDatelDisc(JNIEnv* env,
+ jobject obj);
JNIEXPORT jintArray JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBanner(JNIEnv* env,
jobject obj);
JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBannerWidth(JNIEnv* env,
@@ -154,6 +158,12 @@ JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getRevision
return GetRef(env, obj)->GetRevision();
}
+JNIEXPORT jint JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBlobType(JNIEnv* env,
+ jobject obj)
+{
+ return static_cast(GetRef(env, obj)->GetBlobType());
+}
+
JNIEXPORT jstring JNICALL
Java_org_dolphinemu_dolphinemu_model_GameFile_getBlobTypeString(JNIEnv* env, jobject obj)
{
@@ -175,7 +185,7 @@ Java_org_dolphinemu_dolphinemu_model_GameFile_getCompressionMethod(JNIEnv* env,
JNIEXPORT jboolean JNICALL
Java_org_dolphinemu_dolphinemu_model_GameFile_shouldShowFileFormatDetails(JNIEnv* env, jobject obj)
{
- return GetRef(env, obj)->ShouldShowFileFormatDetails();
+ return static_cast(GetRef(env, obj)->ShouldShowFileFormatDetails());
}
JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getFileSize(JNIEnv* env,
@@ -184,6 +194,12 @@ JNIEXPORT jlong JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getFileSiz
return GetRef(env, obj)->GetFileSize();
}
+JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_isDatelDisc(JNIEnv* env,
+ jobject obj)
+{
+ return static_cast(GetRef(env, obj)->IsDatelDisc());
+}
+
JNIEXPORT jintArray JNICALL Java_org_dolphinemu_dolphinemu_model_GameFile_getBanner(JNIEnv* env,
jobject obj)
{
diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp
index 3dfafacf7c..bef78a49b5 100644
--- a/Source/Android/jni/MainAndroid.cpp
+++ b/Source/Android/jni/MainAndroid.cpp
@@ -18,6 +18,7 @@
#include
#include "Common/AndroidAnalytics.h"
+#include "Common/Assert.h"
#include "Common/CPUDetect.h"
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
@@ -45,7 +46,9 @@
#include "Core/State.h"
#include "Core/WiiUtils.h"
+#include "DiscIO/Blob.h"
#include "DiscIO/Enums.h"
+#include "DiscIO/ScrubbedBlob.h"
#include "DiscIO/Volume.h"
#include "InputCommon/ControllerInterface/Android/Android.h"
@@ -663,6 +666,58 @@ JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_InstallW
return static_cast(WiiUtils::InstallWAD(path));
}
+JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ConvertDiscImage(
+ JNIEnv* env, jobject obj, jstring jInPath, jstring jOutPath, jint jPlatform, jint jFormat,
+ jint jBlockSize, jint jCompression, jint jCompressionLevel, jboolean jScrub)
+{
+ const std::string in_path = GetJString(env, jInPath);
+ const std::string out_path = GetJString(env, jOutPath);
+ const DiscIO::Platform platform = static_cast(jPlatform);
+ const DiscIO::BlobType format = static_cast(jFormat);
+ const DiscIO::WIARVZCompressionType compression =
+ static_cast(jCompression);
+ const bool scrub = static_cast(jScrub);
+
+ std::unique_ptr blob_reader;
+ if (scrub)
+ blob_reader = DiscIO::ScrubbedBlob::Create(in_path);
+ else
+ blob_reader = DiscIO::CreateBlobReader(in_path);
+
+ if (!blob_reader)
+ return static_cast(false);
+
+ const auto callback = [](const std::string& text, float percent) { return true; };
+
+ bool success = false;
+
+ switch (format)
+ {
+ case DiscIO::BlobType::PLAIN:
+ success = DiscIO::ConvertToPlain(blob_reader.get(), in_path, out_path, callback);
+ break;
+
+ case DiscIO::BlobType::GCZ:
+ success =
+ DiscIO::ConvertToGCZ(blob_reader.get(), in_path, out_path,
+ platform == DiscIO::Platform::WiiDisc ? 1 : 0, jBlockSize, callback);
+ break;
+
+ case DiscIO::BlobType::WIA:
+ case DiscIO::BlobType::RVZ:
+ success = DiscIO::ConvertToWIAOrRVZ(blob_reader.get(), in_path, out_path,
+ format == DiscIO::BlobType::RVZ, compression,
+ jCompressionLevel, jBlockSize, callback);
+ break;
+
+ default:
+ ASSERT(false);
+ break;
+ }
+
+ return static_cast(success);
+}
+
JNIEXPORT jstring JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_FormatSize(JNIEnv* env,
jobject obj,
jlong bytes,