mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-25 14:28:34 +00:00
android: Change how apps access their APK's "assets" directory.
Now they can explicitly access it with "assets://" filenames, and SDL_GetBasePath() returns "assets://" Fixes #15347. Fixes #5044.
This commit is contained in:
@@ -212,6 +212,24 @@ Any files you put in the "app/src/main/assets" directory of your project
|
||||
directory will get bundled into the application package and you can load
|
||||
them using the standard functions in SDL_iostream.h.
|
||||
|
||||
As of SDL 3.6.0, SDL APIs, such as SDL_EnumerateDirectory() and
|
||||
SDL_IOFromFile(), understand paths that are prefixed with "assets://" and will
|
||||
look for paths exclusively inside the APK's "assets" directory. Since this is
|
||||
where app-specific data files are meant to be located, SDL_GetBasePath() on
|
||||
Android now returns "assets://" to make this work as expected across platforms.
|
||||
Note that SDL 3.2.28 to 3.6.0 returned "./" on Android, and before that,
|
||||
SDL_GetBasePath() always returned NULL on this platform.
|
||||
|
||||
Obviously, paths prefixed with "assets://" are only useful to SDL; other APIs,
|
||||
like fopen(), will not understand them at all.
|
||||
|
||||
As an alternate approach: SDL APIs on Android treat relative paths in a
|
||||
special way. It will look for files under the path returned by
|
||||
SDL_GetAndroidInternalStoragePath() first, and failing that, will attempt to
|
||||
look for them as if they were prefixed by "assets://", with the relative path
|
||||
starting in the base of the assets tree. Absolute paths never check against
|
||||
internal storage or assets.
|
||||
|
||||
There are also a few Android specific functions that allow you to get other
|
||||
useful paths for saving and loading data:
|
||||
* SDL_GetAndroidInternalStoragePath()
|
||||
|
||||
@@ -1901,9 +1901,16 @@ static APKNode *FindAPKChildNode(APKNode *parent, const char *child)
|
||||
|
||||
static const APKNode *FindAPKNode(const char *constpath)
|
||||
{
|
||||
//SDL_Log("FindAPKNode('%s') ...", constpath);
|
||||
if (SDL_strncmp(constpath, "assets://", 9) == 0) {
|
||||
constpath += 9;
|
||||
}
|
||||
|
||||
APKNode *parent = APKRootNode;
|
||||
if (!parent) {
|
||||
return NULL;
|
||||
} else if (*constpath == '\0') {
|
||||
return parent;
|
||||
}
|
||||
|
||||
const size_t pathlen = SDL_strlen(constpath);
|
||||
@@ -2362,12 +2369,20 @@ static void Internal_Android_Destroy_AssetManager(void)
|
||||
|
||||
static const char *GetAssetPath(const char *path)
|
||||
{
|
||||
if (path && path[0] == '.' && path[1] == '/') {
|
||||
path += 2;
|
||||
while (*path == '/') {
|
||||
++path;
|
||||
}
|
||||
if (!path) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path[0] == '.' && ((path[1] == '/') || (path[1] == '\0'))) {
|
||||
path++;
|
||||
} else if (SDL_strncmp(path, "assets://", 9) == 0) {
|
||||
path += 9;
|
||||
}
|
||||
|
||||
while (*path == '/') {
|
||||
++path;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
@@ -371,20 +371,28 @@ char **SDL_InternalGlobDirectory(const char *path, const char *pattern, SDL_Glob
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if path ends with any slash, chop them off, so we don't confuse the pattern matcher later.
|
||||
char *pathcpy = NULL;
|
||||
size_t pathlen = SDL_strlen(path);
|
||||
if ((pathlen > 1) && ((path[pathlen-1] == '/') || (path[pathlen-1] == '\\'))) {
|
||||
pathcpy = SDL_strdup(path);
|
||||
if (!pathcpy) {
|
||||
return NULL;
|
||||
|
||||
// if path ends with any slash, chop them off, so we don't confuse the pattern matcher later.
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strcmp(path, "assets://") == 0) { // don't chop '//' off this if we're looking for the root of the asset tree.
|
||||
pathlen--; // we'll add a 1 again later.
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if ((pathlen > 1) && ((path[pathlen-1] == '/') || (path[pathlen-1] == '\\'))) {
|
||||
pathcpy = SDL_strdup(path);
|
||||
if (!pathcpy) {
|
||||
return NULL;
|
||||
}
|
||||
char *ptr = &pathcpy[pathlen-1];
|
||||
while ((ptr > pathcpy) && ((*ptr == '/') || (*ptr == '\\'))) {
|
||||
*(ptr--) = '\0';
|
||||
--pathlen;
|
||||
}
|
||||
path = pathcpy;
|
||||
}
|
||||
char *ptr = &pathcpy[pathlen-1];
|
||||
while ((ptr > pathcpy) && ((*ptr == '/') || (*ptr == '\\'))) {
|
||||
*(ptr--) = '\0';
|
||||
--pathlen;
|
||||
}
|
||||
path = pathcpy;
|
||||
}
|
||||
|
||||
if (!pattern) {
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
char *SDL_SYS_GetBasePath(void)
|
||||
{
|
||||
return SDL_strdup("./");
|
||||
return SDL_strdup("assets://");
|
||||
}
|
||||
|
||||
char *SDL_SYS_GetPrefPath(const char *org, const char *app)
|
||||
|
||||
@@ -47,6 +47,13 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback
|
||||
#if defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_IOS)
|
||||
if (*path != '/') {
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (SDL_strncmp(path, "assets://", 9) == 0) {
|
||||
char *pathwithsep = NULL;
|
||||
SDL_asprintf(&pathwithsep, "%s%s", path, (path[SDL_strlen(path) - 1] != '/') ? "/" : "");
|
||||
const bool retval = pathwithsep ? Android_JNI_EnumerateAssetDirectory(pathwithsep, cb, userdata) : false;
|
||||
SDL_free(pathwithsep);
|
||||
return retval;
|
||||
}
|
||||
SDL_asprintf(&apath, "%s/%s", SDL_GetAndroidInternalStoragePath(), path);
|
||||
#elif defined(SDL_PLATFORM_IOS)
|
||||
char *base = SDL_GetPrefPath("", "");
|
||||
@@ -89,14 +96,13 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback
|
||||
|
||||
DIR *dir = opendir(pathwithsep);
|
||||
if (!dir) {
|
||||
#ifdef SDL_PLATFORM_ANDROID // Maybe it's an asset...?
|
||||
#ifdef SDL_PLATFORM_ANDROID // Maybe it's an asset... that didn't use an "assets://" URL?
|
||||
const bool retval = Android_JNI_EnumerateAssetDirectory(pathwithsep + extralen, cb, userdata);
|
||||
SDL_free(pathwithsep);
|
||||
return retval;
|
||||
#else
|
||||
#endif
|
||||
SDL_free(pathwithsep);
|
||||
return SDL_SetError("Can't open directory: %s", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
|
||||
SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
|
||||
@@ -342,6 +348,8 @@ bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info)
|
||||
#ifdef SDL_PLATFORM_ANDROID
|
||||
if (*path == '/') {
|
||||
rc = stat(path, &statbuf);
|
||||
} else if (SDL_strncmp(path, "assets://", 9) == 0) {
|
||||
return Android_JNI_GetAssetPathInfo(path, info);
|
||||
} else {
|
||||
char *apath = NULL;
|
||||
SDL_asprintf(&apath, "%s/%s", SDL_GetAndroidInternalStoragePath(), path);
|
||||
@@ -351,7 +359,7 @@ bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info)
|
||||
rc = stat(apath, &statbuf);
|
||||
SDL_free(apath);
|
||||
}
|
||||
if (rc < 0) {
|
||||
if (rc < 0) { // Maybe it's an asset... that didn't use an "assets://" URL?
|
||||
return Android_JNI_GetAssetPathInfo(path, info);
|
||||
}
|
||||
#elif defined(SDL_PLATFORM_IOS)
|
||||
|
||||
@@ -1021,7 +1021,7 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
|
||||
}
|
||||
|
||||
return SDL_IOFromFP(fp, true);
|
||||
} else {
|
||||
} else if (SDL_strncmp(file, "assets://", 9) != 0) {
|
||||
// Try opening it from internal storage if it's a relative path
|
||||
char *path = NULL;
|
||||
SDL_asprintf(&path, "%s/%s", SDL_GetAndroidInternalStoragePath(), file);
|
||||
@@ -1040,8 +1040,7 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
|
||||
}
|
||||
#endif // HAVE_STDIO_H
|
||||
|
||||
// Try to open the file from the asset system
|
||||
|
||||
// Try to open the file from the asset system?
|
||||
void *iodata = NULL;
|
||||
if (!Android_JNI_FileOpen(&iodata, file, mode)) {
|
||||
return NULL;
|
||||
|
||||
Reference in New Issue
Block a user