FileSelector

This commit is contained in:
Waterdish
2023-10-28 19:23:51 -07:00
parent 2d4b36cae6
commit 9e7d6d2b57
5 changed files with 219 additions and 39 deletions
+5 -1
View File
@@ -337,7 +337,11 @@ target_include_directories(ZAPDLib PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../../../libpng
)
target_link_libraries(ZAPDLib PRIVATE png)
if (CMAKE_SYSTEM_NAME STREQUAL "Android")
target_link_libraries(ZAPDLib PRIVATE png log)
else()
target_link_libraries(ZAPDLib PRIVATE png)
endif()
target_include_directories(${PROJECT_NAME} PRIVATE
+28 -9
View File
@@ -4,6 +4,14 @@
#include "Utils/Path.h"
#include "WarningHandler.h"
#ifdef __ANDROID__
#include <android/log.h>
// Define a custom macro to replace printf with __android_log_print
#define printf(...) __android_log_print(ANDROID_LOG_INFO, "YourTag", __VA_ARGS__)
#endif
#include "ZAnimation.h"
ZNormalAnimation nAnim(nullptr);
ZCurveAnimation cAnim(nullptr);
@@ -306,6 +314,7 @@ extern "C" int zapd_main(int argc, char* argv[])
auto start = std::chrono::steady_clock::now();
int fileListSize = fileList.size();
Globals::Instance->singleThreaded = false;
Globals::Instance->verbosity = VerbosityLevel::VERBOSITY_INFO;
for (int i = 0; i < fileListSize; i++)
Globals::Instance->workerData[i] = new FileWorker();
@@ -327,16 +336,15 @@ extern "C" int zapd_main(int argc, char* argv[])
}
}
if (!Globals::Instance->singleThreaded)
{
while (true)
{
if (numWorkersLeft <= 0)
break;
if (!Globals::Instance->singleThreaded) {
while (true) {
printf("%i", numWorkersLeft);
if (numWorkersLeft <= 0)
break;
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
}
auto end = std::chrono::steady_clock::now();
auto diff =
@@ -422,9 +430,12 @@ int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileM
return 1;
}
printf("%s 1",fileListItem.c_str()); // It's getting stuck here VV. Need to print in Parse?
parseSuccessful = Parse(fileListItem, Globals::Instance->baseRomPath,
Globals::Instance->outputPath, fileMode, workerID);
printf("%s 2",fileListItem.c_str());
if (!parseSuccessful)
return 1;
@@ -443,6 +454,7 @@ int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileM
}
else
{
printf("%s 3",fileListItem.c_str());
for (int i = 0; i < Globals::Instance->workerData[workerID]->files.size(); i++)
{
delete Globals::Instance->workerData[workerID]->files[i];
@@ -464,9 +476,11 @@ int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileM
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,
ZFileMode fileMode, int workerID)
{
printf("%i parse 1",workerID);
tinyxml2::XMLDocument doc;
tinyxml2::XMLError eResult = doc.LoadFile(xmlFilePath.string().c_str());
printf("%i parse 2",workerID);
if (eResult != tinyxml2::XML_SUCCESS)
{
// TODO: use XMLDocument::ErrorIDToName to get more specific error messages here
@@ -475,7 +489,9 @@ bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path
return false;
}
printf("%i parse 3",workerID);
tinyxml2::XMLNode* root = doc.FirstChild();
printf("%i parse 4",workerID);
if (root == nullptr)
{
@@ -485,6 +501,7 @@ bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path
return false;
}
printf("%i parse 5",workerID);
for (tinyxml2::XMLElement* child = root->FirstChildElement(); child != NULL;
child = child->NextSiblingElement())
{
@@ -538,6 +555,7 @@ bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path
HANDLE_ERROR(WarningType::InvalidXML, errorHeader, errorBody);
}
}
printf("%i parse 6",workerID);
if (fileMode != ZFileMode::ExternalFile)
{
@@ -564,6 +582,7 @@ bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path
if (exporterSet != nullptr && exporterSet->endXMLFunc != nullptr)
exporterSet->endXMLFunc();
}
printf("%i parse 7",workerID);
return true;
}
+94 -24
View File
@@ -37,6 +37,11 @@
#define UNREACHABLE __builtin_unreachable();
#endif
#ifdef __ANDROID__
#include <jni.h>
#include <string>
#endif
#include <stdlib.h>
#include <SDL2/SDL_messagebox.h>
@@ -61,27 +66,27 @@ static constexpr uint32_t OOT_PAL_10 = 0xB044B569;
static constexpr uint32_t OOT_PAL_11 = 0xB2055FBD;
static const std::unordered_map<uint32_t, const char*> verMap = {
{ OOT_PAL_GC, "PAL Gamecube" },
{ OOT_PAL_MQ, "PAL MQ" },
{ OOT_PAL_GC_DBG1, "PAL Debug 1" },
{ OOT_PAL_GC_DBG2, "PAL Debug 2" },
{ OOT_PAL_GC_MQ_DBG, "PAL MQ Debug" },
{ OOT_PAL_10, "PAL N64 1.0" },
{ OOT_PAL_11, "PAL N64 1.1" },
{ OOT_PAL_GC, "PAL Gamecube" },
{ OOT_PAL_MQ, "PAL MQ" },
{ OOT_PAL_GC_DBG1, "PAL Debug 1" },
{ OOT_PAL_GC_DBG2, "PAL Debug 2" },
{ OOT_PAL_GC_MQ_DBG, "PAL MQ Debug" },
{ OOT_PAL_10, "PAL N64 1.0" },
{ OOT_PAL_11, "PAL N64 1.1" },
};
// TODO only check the first 54MB of the rom.
static constexpr std::array<const uint32_t, 10> goodCrcs = {
0xfa8c0555, // MQ DBG 64MB (Original overdump)
0x8652ac4c, // MQ DBG 64MB
0x5B8A1EB7, // MQ DBG 64MB (Empty overdump)
0x1f731ffe, // MQ DBG 54MB
0x044b3982, // NMQ DBG 54MB
0xEB15D7B9, // NMQ DBG 64MB
0xDA8E61BF, // GC PAL
0x7A2FAE68, // GC MQ PAL
0xFD9913B1, // N64 PAL 1.0
0xE033FBBA, // N64 PAL 1.1
0xfa8c0555, // MQ DBG 64MB (Original overdump)
0x8652ac4c, // MQ DBG 64MB
0x5B8A1EB7, // MQ DBG 64MB (Empty overdump)
0x1f731ffe, // MQ DBG 54MB
0x044b3982, // NMQ DBG 54MB
0xEB15D7B9, // NMQ DBG 64MB
0xDA8E61BF, // GC PAL
0x7A2FAE68, // GC MQ PAL
0xFD9913B1, // N64 PAL 1.0
0xE033FBBA, // N64 PAL 1.1
};
enum class ButtonId : int {
@@ -90,6 +95,27 @@ enum class ButtonId : int {
FIND,
};
#ifdef __ANDROID__
const char* javaRomPath = NULL;
bool fileDialogOpen = false;
//function to be called from C
void openFilePickerFromC(JNIEnv* env, jobject javaObject) {
fileDialogOpen = true;
jclass javaClass = env->GetObjectClass(javaObject);
jmethodID openFilePickerMethod = env->GetMethodID(javaClass, "openFilePicker", "()V");
env->CallVoidMethod(javaObject, openFilePickerMethod);
}
// Define the native method to handle the selected file path
extern "C" void JNICALL Java_com_dishii_soh_MainActivity_nativeHandleSelectedFile(JNIEnv* env, jobject obj, jstring filePath) {
const char* filePathStr = env->GetStringUTFChars(filePath, 0);
javaRomPath = strdup(filePathStr); // save filepath to string
fileDialogOpen = false;
env->ReleaseStringUTFChars(filePath, filePathStr);
}
#endif
void Extractor::ShowErrorBox(const char* title, const char* text) {
#ifdef _WIN32
@@ -324,16 +350,35 @@ bool Extractor::GetRomPathFromBox() {
return false;
}
mCurrentRomPath = nameBuffer;
#else
auto selection = pfd::open_file("Select a file", ".", { "N64 Roms", "*.z64 *.n64 *.v64" }).result();
#else
#ifndef __ANDROID__
auto selection = pfd::open_file("Select a file", ".", { "N64 Roms", "*.z64 *.n64 *.v64" }).result();
#else
JNIEnv* javaEnv = (JNIEnv*)SDL_AndroidGetJNIEnv();
jobject javaObject = (jobject)SDL_AndroidGetActivity();
std::vector<std::string> selection;
openFilePickerFromC(javaEnv, javaObject);
while(fileDialogOpen){
//Do nothing until it's chosen
SDL_Delay(250);
}
SDL_Log("%s",javaRomPath);
selection.push_back(javaRomPath);
#endif
if (selection.empty()) {
return false;
}
mCurrentRomPath = selection[0];
#endif
#endif
mCurRomSize = GetCurRomSize();
#ifdef __ANDROID__
if (javaRomPath) {
free((void*)javaRomPath);
javaRomPath = NULL;
}
#endif
return true;
}
@@ -414,7 +459,7 @@ bool Extractor::ManuallySearchForRomMatchingType(RomSearchMode searchMode) {
char msgBuf[150];
snprintf(msgBuf, 150, "The selected rom does not match the expected game type\nExpected type: %s.\n\nDo you want to search again?",
searchMode == RomSearchMode::MQ ? "Master Quest" : "Vanilla");
searchMode == RomSearchMode::MQ ? "Master Quest" : "Vanilla");
while ((searchMode == RomSearchMode::Vanilla && IsMasterQuest()) ||
(searchMode == RomSearchMode::MQ && !IsMasterQuest())) {
@@ -542,8 +587,12 @@ const char* Extractor::GetZapdVerStr() const {
}
std::string Extractor::Mkdtemp() {
std::string temp_dir = SDL_AndroidGetExternalStoragePath();//std::filesystem::temp_directory_path().string();
#ifndef __ANDROID__
std::string temp_dir = std::filesystem::temp_directory_path().string();
#else
std::string temp_dir = SDL_AndroidGetExternalStoragePath();
#endif
// create 6 random alphanumeric characters
static const char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
std::random_device rd;
@@ -581,9 +630,12 @@ bool Extractor::CallZapd(std::string installPath, std::string exportdir) {
std::filesystem::copy(installPath + "/assets", tempdir + "/assets",
std::filesystem::copy_options::recursive | std::filesystem::copy_options::update_existing);
#else
//std::filesystem::create_symlink(installPath + "/assets", tempdir + "/assets");
#ifndef __ANDROID__
std::filesystem::create_symlink(installPath + "/assets", tempdir + "/assets");
#else
std::filesystem::copy(installPath + "/assets", tempdir + "/assets",
std::filesystem::copy_options::recursive | std::filesystem::copy_options::update_existing);
#endif
#endif
std::filesystem::current_path(tempdir);
@@ -617,8 +669,26 @@ bool Extractor::CallZapd(std::string installPath, std::string exportdir) {
SetWindowPos(cmdWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
#endif
#ifdef __ANDROID__
int ret;
SDL_MessageBoxData boxData = { 0 };
SDL_MessageBoxButtonData buttons[2] = { { 0 } };
buttons[0].buttonid = IDYES;
buttons[0].text = "Ok";
buttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
boxData.numbuttons = 1;
boxData.flags = SDL_MESSAGEBOX_INFORMATION;
boxData.message = "The screen will go black for at least 30 seconds, but it could take up to 3 minutes.";
boxData.title = "Starting Extraction";
boxData.buttons = buttons;
SDL_ShowMessageBox(&boxData, &ret);
#endif
zapd_main(argc, (char**)argv.data());
SDL_Log("zapd_main finished");
#ifdef _WIN32
// Hide the command window again.
ShowWindow(cmdWindow, SW_HIDE);
+3 -3
View File
@@ -49,8 +49,8 @@
<!-- Allow access to the vibrator -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- if you want to capture audio, uncomment this. -->
<!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
@@ -80,7 +80,7 @@
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:preferMinimalPostProcessing="true"
android:exported="true"
android:screenOrientation="landscape"
android:screenOrientation="userLandscape"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -18,14 +18,54 @@ import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.util.Log;
//This class is the main SDLActivity
//This class is the main SDLActivity and just sets up a bunch of default files
public class MainActivity extends SDLActivity{
private static final int STORAGE_PERMISSION_REQUEST_CODE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Check if folder/file exists and if it doesn't, create it
// Check if storage permissions are granted
if (hasStoragePermission()) {
setupFiles();
} else {
requestStoragePermission();
}
}
// Check if storage permission is granted
private boolean hasStoragePermission() {
return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED;
}
// Request storage permission
private void requestStoragePermission() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
STORAGE_PERMISSION_REQUEST_CODE);
}
// Handle permission request result
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == STORAGE_PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
setupFiles();
} else {
// Permission denied, handle accordingly (e.g., show a message)
}
}
}
private void setupFiles(){
File externalAssetsDir = new File(getExternalFilesDir(null), "assets");
if (!externalAssetsDir.exists()) {
try {
@@ -57,4 +97,51 @@ public class MainActivity extends SDLActivity{
}
private native void nativeHandleSelectedFile(String filePath);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == RESULT_OK) {
Uri selectedFileUri = data.getData();
String fileName = "ZELOOTD.z64";
File destinationDirectory = getExternalFilesDir(null); // The second argument can specify a subdirectory, or you can pass null to use the root directory.
File destinationFile = new File(destinationDirectory, fileName);
if (destinationDirectory != null) {
try {
InputStream in = getContentResolver().openInputStream(selectedFileUri);
OutputStream out = new FileOutputStream(destinationFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
nativeHandleSelectedFile(destinationFile.getPath());
}
}
public void openFilePicker() {
// Create an Intent to open the file picker dialog
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("*/*");
// Start the file picker dialog
startActivityForResult(intent, 0);
}
// Check if external storage is available and writable
private boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}
}