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.
This commit is contained in:
Henrik Rydgård 2023-05-16 16:05:58 +02:00
parent 07a96b8734
commit 081bdb323a
3 changed files with 44 additions and 10 deletions

View file

@ -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);

View file

@ -66,4 +66,8 @@ public:
const std::string &RootPath() const {
return root.empty() ? file : root;
}
bool IsTreeURI() const {
return !root.empty();
}
};

View file

@ -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;
}