Skip to content

Commit fcdc2cb

Browse files
committed
android: Change how apps access their APK's "assets" directory.
Now they can explicitly access it with "assets://" filenames, and optionally turn off the fallback to checking assets if the native filesystem is missing a file.
1 parent 41f0794 commit fcdc2cb

5 files changed

Lines changed: 105 additions & 44 deletions

File tree

include/SDL3/SDL_hints.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,33 @@ extern "C" {
6565
*/
6666
#define SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED "SDL_ALLOW_ALT_TAB_WHILE_GRABBED"
6767

68+
/**
69+
* A variable to control if Android will fallback to accessing the app's APK.
70+
*
71+
* By default, on Android, several SDL APIs will attempt to work with files
72+
* and directories on the real filesystem, but if those files cannot be found,
73+
* SDL will attempt to locate them inside the "assets" folder in the app's APK
74+
* archive. This can cause confusion when files show up in unexpected
75+
* locations, or cause an unexpected override.
76+
*
77+
* As of SDL 3.4.6, the APK's assets can be accessed explicitly with the
78+
* "assets://" URL scheme, making the existing behavior undesirable.
79+
*
80+
* This hint can change the behavior so that APK assets are only accessible
81+
* by prepending "assets://" to a file path. As this is a change in behavior,
82+
* the hint defaults to "1" to operate as usual.
83+
*
84+
* The variable can be set to the following values:
85+
*
86+
* - "0": SDL will _not_ fall back to the APK assets.
87+
* - "1": SDL will fall back to the APK assets. (default)
88+
*
89+
* This hint can be set anytime.
90+
*
91+
* \since This hint is available since SDL 3.4.6.
92+
*/
93+
#define SDL_HINT_ANDROID_ALLOW_ASSET_DIR_FALLBACK "SDL_ANDROID_ALLOW_ASSET_DIR_FALLBACK"
94+
6895
/**
6996
* A variable to control whether the SDL activity is allowed to be re-created.
7097
*

src/core/android/SDL_android.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,9 +1880,16 @@ static APKNode *FindAPKChildNode(APKNode *parent, const char *child)
18801880

18811881
static const APKNode *FindAPKNode(const char *constpath)
18821882
{
1883+
//SDL_Log("FindAPKNode('%s') ...", constpath);
1884+
if (SDL_strncmp(constpath, "assets://", 9) == 0) {
1885+
constpath += 9;
1886+
}
1887+
18831888
APKNode *parent = APKRootNode;
18841889
if (!parent) {
18851890
return NULL;
1891+
} else if (*constpath == '\0') {
1892+
return parent;
18861893
}
18871894

18881895
const size_t pathlen = SDL_strlen(constpath);
@@ -2341,12 +2348,20 @@ static void Internal_Android_Destroy_AssetManager(void)
23412348

23422349
static const char *GetAssetPath(const char *path)
23432350
{
2344-
if (path && path[0] == '.' && path[1] == '/') {
2345-
path += 2;
2346-
while (*path == '/') {
2347-
++path;
2348-
}
2351+
if (!path) {
2352+
return NULL;
23492353
}
2354+
2355+
if (path[0] == '.' && ((path[1] == '/') || (path[1] == '\0'))) {
2356+
path++;
2357+
} else if (SDL_strncmp(path, "assets://", 9) == 0) {
2358+
path += 9;
2359+
}
2360+
2361+
while (*path == '/') {
2362+
++path;
2363+
}
2364+
23502365
return path;
23512366
}
23522367

src/filesystem/SDL_filesystem.c

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -371,20 +371,28 @@ char **SDL_InternalGlobDirectory(const char *path, const char *pattern, SDL_Glob
371371
return NULL;
372372
}
373373

374-
// if path ends with any slash, chop them off, so we don't confuse the pattern matcher later.
375374
char *pathcpy = NULL;
376375
size_t pathlen = SDL_strlen(path);
377-
if ((pathlen > 1) && ((path[pathlen-1] == '/') || (path[pathlen-1] == '\\'))) {
378-
pathcpy = SDL_strdup(path);
379-
if (!pathcpy) {
380-
return NULL;
381-
}
382-
char *ptr = &pathcpy[pathlen-1];
383-
while ((ptr > pathcpy) && ((*ptr == '/') || (*ptr == '\\'))) {
384-
*(ptr--) = '\0';
385-
--pathlen;
376+
377+
// if path ends with any slash, chop them off, so we don't confuse the pattern matcher later.
378+
#ifdef SDL_PLATFORM_ANDROID
379+
if (SDL_strcmp(path, "assets://") == 0) { // don't chop '//' off this if we're looking for the root of the asset tree.
380+
pathlen--; // we'll add a 1 again later.
381+
} else
382+
#endif
383+
{
384+
if ((pathlen > 1) && ((path[pathlen-1] == '/') || (path[pathlen-1] == '\\'))) {
385+
pathcpy = SDL_strdup(path);
386+
if (!pathcpy) {
387+
return NULL;
388+
}
389+
char *ptr = &pathcpy[pathlen-1];
390+
while ((ptr > pathcpy) && ((*ptr == '/') || (*ptr == '\\'))) {
391+
*(ptr--) = '\0';
392+
--pathlen;
393+
}
394+
path = pathcpy;
386395
}
387-
path = pathcpy;
388396
}
389397

390398
if (!pattern) {

src/filesystem/posix/SDL_sysfsops.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback
4747
#if defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_IOS)
4848
if (*path != '/') {
4949
#ifdef SDL_PLATFORM_ANDROID
50+
if (SDL_strncmp(path, "assets://", 9) == 0) {
51+
char *pathwithsep = NULL;
52+
SDL_asprintf(&pathwithsep, "%s%s", path, (path[SDL_strlen(path) - 1] != '/') ? "/" : "");
53+
const bool retval = pathwithsep ? Android_JNI_EnumerateAssetDirectory(pathwithsep, cb, userdata) : false;
54+
SDL_free(pathwithsep);
55+
return retval;
56+
}
5057
SDL_asprintf(&apath, "%s/%s", SDL_GetAndroidInternalStoragePath(), path);
5158
#elif defined(SDL_PLATFORM_IOS)
5259
char *base = SDL_GetPrefPath("", "");
@@ -89,14 +96,15 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback
8996

9097
DIR *dir = opendir(pathwithsep);
9198
if (!dir) {
92-
#ifdef SDL_PLATFORM_ANDROID // Maybe it's an asset...?
93-
const bool retval = Android_JNI_EnumerateAssetDirectory(pathwithsep + extralen, cb, userdata);
94-
SDL_free(pathwithsep);
95-
return retval;
96-
#else
99+
#ifdef SDL_PLATFORM_ANDROID // Maybe it's an asset... that didn't use an "assets://" URL?
100+
if (SDL_GetHintBoolean(SDL_HINT_ANDROID_ALLOW_ASSET_DIR_FALLBACK, true)) {
101+
const bool retval = Android_JNI_EnumerateAssetDirectory(pathwithsep + extralen, cb, userdata);
102+
SDL_free(pathwithsep);
103+
return retval;
104+
}
105+
#endif
97106
SDL_free(pathwithsep);
98107
return SDL_SetError("Can't open directory: %s", strerror(errno));
99-
#endif
100108
}
101109

102110
SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
@@ -342,6 +350,8 @@ bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info)
342350
#ifdef SDL_PLATFORM_ANDROID
343351
if (*path == '/') {
344352
rc = stat(path, &statbuf);
353+
} else if (SDL_strncmp(path, "assets://", 9) == 0) {
354+
return Android_JNI_GetAssetPathInfo(path, info);
345355
} else {
346356
char *apath = NULL;
347357
SDL_asprintf(&apath, "%s/%s", SDL_GetAndroidInternalStoragePath(), path);
@@ -351,7 +361,7 @@ bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info)
351361
rc = stat(apath, &statbuf);
352362
SDL_free(apath);
353363
}
354-
if (rc < 0) {
364+
if ((rc < 0) && SDL_GetHintBoolean(SDL_HINT_ANDROID_ALLOW_ASSET_DIR_FALLBACK, true)) {
355365
return Android_JNI_GetAssetPathInfo(path, info);
356366
}
357367
#elif defined(SDL_PLATFORM_IOS)

src/io/SDL_iostream.c

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
10211021
}
10221022

10231023
return SDL_IOFromFP(fp, true);
1024-
} else {
1024+
} else if (SDL_strncmp(file, "assets://", 9) != 0) {
10251025
// Try opening it from internal storage if it's a relative path
10261026
char *path = NULL;
10271027
SDL_asprintf(&path, "%s/%s", SDL_GetAndroidInternalStoragePath(), file);
@@ -1041,27 +1041,28 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
10411041
#endif // HAVE_STDIO_H
10421042

10431043
// Try to open the file from the asset system
1044+
if ((SDL_strncmp(file, "assets://", 9) == 0) || SDL_GetHintBoolean(SDL_HINT_ANDROID_ALLOW_ASSET_DIR_FALLBACK, true)) {
1045+
void *iodata = NULL;
1046+
if (!Android_JNI_FileOpen(&iodata, file, mode)) {
1047+
return NULL;
1048+
}
10441049

1045-
void *iodata = NULL;
1046-
if (!Android_JNI_FileOpen(&iodata, file, mode)) {
1047-
return NULL;
1048-
}
1049-
1050-
SDL_IOStreamInterface iface;
1051-
SDL_INIT_INTERFACE(&iface);
1052-
iface.size = Android_JNI_FileSize;
1053-
iface.seek = Android_JNI_FileSeek;
1054-
iface.read = Android_JNI_FileRead;
1055-
iface.write = Android_JNI_FileWrite;
1056-
iface.close = Android_JNI_FileClose;
1057-
1058-
iostr = SDL_OpenIO(&iface, iodata);
1059-
if (!iostr) {
1060-
iface.close(iodata);
1061-
} else {
1062-
const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
1063-
if (props) {
1064-
SDL_SetPointerProperty(props, SDL_PROP_IOSTREAM_ANDROID_AASSET_POINTER, iodata);
1050+
SDL_IOStreamInterface iface;
1051+
SDL_INIT_INTERFACE(&iface);
1052+
iface.size = Android_JNI_FileSize;
1053+
iface.seek = Android_JNI_FileSeek;
1054+
iface.read = Android_JNI_FileRead;
1055+
iface.write = Android_JNI_FileWrite;
1056+
iface.close = Android_JNI_FileClose;
1057+
1058+
iostr = SDL_OpenIO(&iface, iodata);
1059+
if (!iostr) {
1060+
iface.close(iodata);
1061+
} else {
1062+
const SDL_PropertiesID props = SDL_GetIOProperties(iostr);
1063+
if (props) {
1064+
SDL_SetPointerProperty(props, SDL_PROP_IOSTREAM_ANDROID_AASSET_POINTER, iodata);
1065+
}
10651066
}
10661067
}
10671068

0 commit comments

Comments
 (0)