From 081bdb323a42bf2b18f9e103381e64e36d27eafd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 16 May 2023 16:05:58 +0200 Subject: [PATCH 1/2] Fix running some file formats from the Downloads folder Due to how we mount stuff, we need to be able to navigate one step up from the executable, and then re-attach the executable filename. To allow this, in content URIs, treat ':' as a directory separator for navigation purposes. End result, you can now download cube.elf from the website and run it directly from Downloads without using a file manager to move it. --- Common/File/AndroidContentURI.cpp | 36 +++++++++++++++++++++++++------ Common/File/AndroidContentURI.h | 4 ++++ unittest/UnitTest.cpp | 14 ++++++++---- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/Common/File/AndroidContentURI.cpp b/Common/File/AndroidContentURI.cpp index 65526285ecf8..766dfa4446db 100644 --- a/Common/File/AndroidContentURI.cpp +++ b/Common/File/AndroidContentURI.cpp @@ -62,7 +62,16 @@ AndroidContentURI AndroidContentURI::WithRootFilePath(const std::string &filePat AndroidContentURI AndroidContentURI::WithComponent(const std::string &filePath) { AndroidContentURI uri = *this; - uri.file = uri.file + "/" + filePath; + if (uri.file.empty()) { + // Not sure what to do. + return uri; + } + if (uri.file.back() == ':') { + // Special case handling for Document URIs: Treat the ':' as a directory separator too (but preserved in the filename). + uri.file = uri.file + filePath; + } else { + uri.file = uri.file + "/" + filePath; + } return uri; } @@ -94,10 +103,11 @@ AndroidContentURI AndroidContentURI::WithReplacedExtension(const std::string &ne } bool AndroidContentURI::CanNavigateUp() const { - if (root.empty()) { - return false; + if (IsTreeURI()) { + return file.size() > root.size(); + } else { + return file.find(':') != std::string::npos && file.back() != ':'; } - return file.size() > root.size(); } // Only goes downwards in hierarchies. No ".." will ever be generated. @@ -138,6 +148,9 @@ std::string AndroidContentURI::GetLastPart() const { if (!CanNavigateUp()) { size_t colon = file.rfind(':'); + if (file.back() == ':') { + return file; + } if (colon == std::string::npos) { return std::string(); } @@ -146,7 +159,12 @@ std::string AndroidContentURI::GetLastPart() const { size_t slash = file.rfind('/'); if (slash == std::string::npos) { - return std::string(); + // ok, look for the final colon. If it's the last char, we would have been caught above in !CanNavigateUp. + size_t colon = file.rfind(':'); + if (colon == std::string::npos) { + return std::string(); + } + return file.substr(colon + 1); } std::string part = file.substr(slash + 1); @@ -160,7 +178,13 @@ bool AndroidContentURI::NavigateUp() { size_t slash = file.rfind('/'); if (slash == std::string::npos) { - return false; + // ok, look for the final colon. + size_t colon = file.rfind(':'); + if (colon == std::string::npos) { + return false; + } + file = file.substr(0, colon + 1); // Note: we include the colon in these paths. + return true; } file = file.substr(0, slash); diff --git a/Common/File/AndroidContentURI.h b/Common/File/AndroidContentURI.h index 3020b4147654..23ce2a9e03ce 100644 --- a/Common/File/AndroidContentURI.h +++ b/Common/File/AndroidContentURI.h @@ -66,4 +66,8 @@ class AndroidContentURI { const std::string &RootPath() const { return root.empty() ? file : root; } + + bool IsTreeURI() const { + return !root.empty(); + } }; diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index 2aa53e852608..88de9eab71ba 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -722,14 +722,20 @@ static bool TestAndroidContentURI() { EXPECT_EQ_STR(diff, std::string("Tekken 6.iso")); EXPECT_EQ_STR(fileURI.GetFileExtension(), std::string(".prx")); - EXPECT_FALSE(fileURI.CanNavigateUp()); + EXPECT_TRUE(fileURI.CanNavigateUp()); // Can now virtually navigate up one step from these. - // These are annoying because they hide the actual filename, and we can't get at a parent folder, - // which confuses our elf loading. + // These are annoying because they hide the actual filename, and we can't get at a parent folder. + // Decided to handle the ':' as a directory separator for navigation purposes, which fixes the problem (though not the extension thing). AndroidContentURI downloadURI; EXPECT_TRUE(downloadURI.Parse(std::string(downloadURIString))); EXPECT_EQ_STR(downloadURI.GetLastPart(), std::string("10000000006")); - EXPECT_FALSE(downloadURI.CanNavigateUp()); + EXPECT_TRUE(downloadURI.CanNavigateUp()); + EXPECT_TRUE(downloadURI.NavigateUp()); + // While this is not an openable valid content URI, we can still get something that we can concatenate a filename on top of. + EXPECT_EQ_STR(downloadURI.ToString(), std::string("content://com.android.providers.downloads.documents/document/msf%3A")); + EXPECT_EQ_STR(downloadURI.GetLastPart(), std::string("msf:")); + downloadURI = downloadURI.WithComponent("myfile"); + EXPECT_EQ_STR(downloadURI.ToString(), std::string("content://com.android.providers.downloads.documents/document/msf%3Amyfile")); return true; } From 444897a8b82d437d7521ced8ab6c357086ecc7b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 16 May 2023 18:25:31 +0200 Subject: [PATCH 2/2] Some reordering to make the code make more sense (no actual effect) --- Common/File/AndroidContentURI.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/File/AndroidContentURI.cpp b/Common/File/AndroidContentURI.cpp index 766dfa4446db..6456b8cad209 100644 --- a/Common/File/AndroidContentURI.cpp +++ b/Common/File/AndroidContentURI.cpp @@ -148,12 +148,12 @@ std::string AndroidContentURI::GetLastPart() const { if (!CanNavigateUp()) { size_t colon = file.rfind(':'); - if (file.back() == ':') { - return file; - } if (colon == std::string::npos) { return std::string(); } + if (file.back() == ':') { + return file; + } return file.substr(colon + 1); }