comparison util.c @ 2681:c4256ce2c45a

Updated Android port using gradle toolchain and with basic Storage Access Framework support for Android 11+ support
author Michael Pavone <pavone@retrodev.com>
date Wed, 26 Mar 2025 01:20:55 -0700
parents bebc3589dedf
children 143cb5762ec9
comparison
equal deleted inserted replaced
2680:e3394457427e 2681:c4256ce2c45a
9 #include <sys/stat.h> 9 #include <sys/stat.h>
10 #include <errno.h> 10 #include <errno.h>
11 11
12 #ifdef __ANDROID__ 12 #ifdef __ANDROID__
13 #include <android/log.h> 13 #include <android/log.h>
14 #include <SDL_system.h>
15 #include <jni.h>
14 #define info_puts(msg) __android_log_write(ANDROID_LOG_INFO, "BlastEm", msg) 16 #define info_puts(msg) __android_log_write(ANDROID_LOG_INFO, "BlastEm", msg)
15 #define warning_puts(msg) __android_log_write(ANDROID_LOG_WARN, "BlastEm", msg) 17 #define warning_puts(msg) __android_log_write(ANDROID_LOG_WARN, "BlastEm", msg)
16 #define fatal_puts(msg) __android_log_write(ANDROID_LOG_FATAL, "BlastEm", msg) 18 #define fatal_puts(msg) __android_log_write(ANDROID_LOG_FATAL, "BlastEm", msg)
17 19
18 #define info_printf(msg, args) __android_log_vprint(ANDROID_LOG_INFO, "BlastEm", msg, args) 20 #define info_printf(msg, args) __android_log_vprint(ANDROID_LOG_INFO, "BlastEm", msg, args)
864 } 866 }
865 #include <dirent.h> 867 #include <dirent.h>
866 868
867 dir_entry *get_dir_list(char *path, size_t *numret) 869 dir_entry *get_dir_list(char *path, size_t *numret)
868 { 870 {
871 #ifdef __ANDROID__
872 debug_message("get_dir_list(%s)\n", path);
873 if (startswith(path, "content://")) {
874 static const char activity_class_name[] = "com/retrodev/blastem/BlastEmActivity";
875 static const char read_uri_dir_name[] = "readUriDir";
876 JNIEnv *env = SDL_AndroidGetJNIEnv();
877 jclass act_class = (*env)->FindClass(env, activity_class_name);
878 if (!act_class) {
879 fatal_error("Failed to find activity class %s\n", activity_class_name);
880 }
881 jmethodID meth = (*env)->GetMethodID(env, act_class, read_uri_dir_name, "(Ljava/lang/String;)[Ljava/lang/String;");
882 if (!meth) {
883 fatal_error("Failed to find method %s\n", read_uri_dir_name);
884 }
885 debug_message("get_dir_list(%s) using Storage Access Framework\n", path);
886 jstring jpath = (*env)->NewStringUTF(env, path);
887 jobject activity = SDL_AndroidGetActivity();
888 jobject ret = (*env)->CallObjectMethod(env, activity, meth, jpath);
889 dir_entry *res = NULL;
890 if (ret) {
891 jsize num = (*env)->GetArrayLength(env, ret);
892 if (numret) {
893 *numret = num;
894 }
895 res = calloc(num, sizeof(dir_entry));
896 for (jsize i = 0; i < num; i++)
897 {
898 jstring entry = (*env)->GetObjectArrayElement(env, ret, i);
899 char const *tmp = (*env)->GetStringUTFChars(env, entry, NULL);
900 jsize len = (*env)->GetStringUTFLength(env, entry);
901 res[i].name = calloc(len + 1, 1);
902 res[i].is_dir = tmp[len-1] == '/';
903 memcpy(res[i].name, tmp, res[i].is_dir ? len -1 : len);
904 (*env)->ReleaseStringUTFChars(env, entry, tmp);
905 }
906 (*env)->DeleteLocalRef(env, ret);
907 }
908
909 (*env)->DeleteLocalRef(env, activity);
910 if (!res) {
911 if (numret) {
912 *numret = 0;
913 }
914 return NULL;
915 }
916 return res;
917 }
918 #endif
869 DIR *d = opendir(path); 919 DIR *d = opendir(path);
870 if (!d) { 920 if (!d) {
871 if (numret) { 921 if (numret) {
872 *numret = 0; 922 *numret = 0;
873 } 923 }
1002 ret = NULL; 1052 ret = NULL;
1003 } 1053 }
1004 SDL_RWclose(rw); 1054 SDL_RWclose(rw);
1005 return ret; 1055 return ret;
1006 } 1056 }
1007 #endif 1057
1058 static int open_uri(const char *path, const char *mode)
1059 {
1060 static const char activity_class_name[] = "com/retrodev/blastem/BlastEmActivity";
1061 static const char open_uri_as_fd_name[] = "openUriAsFd";
1062 JNIEnv *env = SDL_AndroidGetJNIEnv();
1063 jclass act_class = (*env)->FindClass(env, activity_class_name);
1064 if (!act_class) {
1065 fatal_error("Failed to find activity class %s\n", activity_class_name);
1066 }
1067 jmethodID meth = (*env)->GetMethodID(env, act_class, open_uri_as_fd_name, "(Ljava/lang/String;Ljava/lang/String;)I");
1068 if (!meth) {
1069 fatal_error("Failed to find method %s\n", open_uri_as_fd_name);
1070 }
1071 jobject activity = SDL_AndroidGetActivity();
1072 jstring jpath = (*env)->NewStringUTF(env, path);
1073 jstring jmode = (*env)->NewStringUTF(env, mode);
1074 int fd = (*env)->CallIntMethod(env, activity, meth, jpath, jmode);
1075 (*env)->DeleteLocalRef(env, activity);
1076 return fd;
1077 }
1078
1079 FILE* fopen_wrapper(const char *path, const char *mode)
1080 {
1081 if (startswith(path, "content://")) {
1082 debug_message("fopen_wrapper(%s, %s) - Using Storage Access Framework\n", path, mode);
1083 int fd = open_uri(path, mode);
1084 if (!fd) {
1085 return NULL;
1086 }
1087 return fdopen(fd, mode);
1088 } else {
1089 debug_message("fopen_wrapper(%s, %s) - Norma fopen\n", path, mode);
1090 return fopen(path, mode);
1091 }
1092 }
1093
1094 #ifndef DISABLE_ZLIB
1095 gzFile gzopen_wrapper(const char *path, const char *mode)
1096 {
1097 if (startswith(path, "content://")) {
1098 debug_message("gzopen_wrapper(%s, %s) - Using Storage Access Framework\n", path, mode);
1099 int fd = open_uri(path, mode);
1100 if (!fd) {
1101 return NULL;
1102 }
1103 return gzdopen(fd, mode);
1104 } else {
1105 debug_message("fopen_wrapper(%s, %s) - Norma gzopen\n", path, mode);
1106 return gzopen(path, mode);
1107 }
1108 }
1109 #endif
1110 #endif // IS_LIB
1008 1111
1009 char const *get_config_dir() 1112 char const *get_config_dir()
1010 { 1113 {
1011 return SDL_AndroidGetInternalStoragePath(); 1114 return SDL_AndroidGetInternalStoragePath();
1012 } 1115 }