Browse Source

Fixed filesystem operations on iOS

Full paths are used as-is, relative paths are prepended with a writable path, SDL_GetPrefPath("", ""), since the current directory isn't writable.
Sam Lantinga 2 weeks ago
parent
commit
9f9952d53a
2 changed files with 140 additions and 1 deletions
  1. 107 0
      src/filesystem/posix/SDL_sysfsops.c
  2. 33 1
      src/io/SDL_iostream.c

+ 107 - 0
src/filesystem/posix/SDL_sysfsops.c

@@ -56,6 +56,27 @@ bool SDL_SYS_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback
     }
 #endif
 
+#ifdef SDL_PLATFORM_IOS
+    if (*path != '/') {
+        char *base = SDL_GetPrefPath("", "");
+        if (!base) {
+            return false;
+        }
+
+        char *apath = NULL;
+        SDL_asprintf(&apath, "%s%s", base, path);
+        SDL_free(base);
+        if (!apath) {
+            return false;
+        }
+        const bool retval = SDL_SYS_EnumerateDirectory(apath, cb, userdata);
+        SDL_free(apath);
+        if (retval) {
+            return true;
+        }
+    }
+#endif
+
     char *pathwithsep = NULL;
     int pathwithseplen = SDL_asprintf(&pathwithsep, "%s/", path);
     if ((pathwithseplen == -1) || (!pathwithsep)) {
@@ -117,6 +138,24 @@ bool SDL_SYS_RemovePath(const char *path)
         rc = remove(apath);
         SDL_free(apath);
     }
+#elif defined(SDL_PLATFORM_IOS)
+    if (*path == '/') {
+        rc = remove(path);
+    } else {
+        char *base = SDL_GetPrefPath("", "");
+        if (!base) {
+            return false;
+        }
+
+        char *apath = NULL;
+        SDL_asprintf(&apath, "%s%s", base, path);
+        SDL_free(base);
+        if (!apath) {
+            return false;
+        }
+        rc = remove(apath);
+        SDL_free(apath);
+    }
 #else
     rc = remove(path);
 #endif
@@ -155,6 +194,38 @@ bool SDL_SYS_RenamePath(const char *oldpath, const char *newpath)
     rc = rename(oldpath, newpath);
     SDL_free(aoldpath);
     SDL_free(anewpath);
+#elif defined(SDL_PLATFORM_IOS)
+    char *base = NULL;
+    if (*oldpath != '/' || *newpath != '/') {
+        base = SDL_GetPrefPath("", "");
+        if (!base) {
+            return false;
+        }
+    }
+
+    char *aoldpath = NULL;
+    char *anewpath = NULL;
+    if (*oldpath != '/') {
+        SDL_asprintf(&aoldpath, "%s%s", base, oldpath);
+        if (!aoldpath) {
+            SDL_free(base);
+            return false;
+        }
+        oldpath = aoldpath;
+    }
+    if (*newpath != '/') {
+        SDL_asprintf(&anewpath, "%s%s", base, newpath);
+        if (!anewpath) {
+            SDL_free(base);
+            SDL_free(aoldpath);
+            return false;
+        }
+        newpath = anewpath;
+    }
+    rc = rename(oldpath, newpath);
+    SDL_free(base);
+    SDL_free(aoldpath);
+    SDL_free(anewpath);
 #else
     rc = rename(oldpath, newpath);
 #endif
@@ -235,6 +306,24 @@ bool SDL_SYS_CreateDirectory(const char *path)
         rc = mkdir(apath, 0770);
         SDL_free(apath);
     }
+#elif defined(SDL_PLATFORM_IOS)
+    if (*path == '/') {
+        rc = mkdir(path, 0770);
+    } else {
+        char *base = SDL_GetPrefPath("", "");
+        if (!base) {
+            return false;
+        }
+
+        char *apath = NULL;
+        SDL_asprintf(&apath, "%s%s", base, path);
+        SDL_free(base);
+        if (!apath) {
+            return false;
+        }
+        rc = mkdir(apath, 0770);
+        SDL_free(apath);
+    }
 #else
     rc = mkdir(path, 0770);
 #endif
@@ -271,6 +360,24 @@ bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info)
     if (rc < 0) {
         return Android_JNI_GetAssetPathInfo(path, info);
     }
+#elif defined(SDL_PLATFORM_IOS)
+    if (*path == '/') {
+        rc = stat(path, &statbuf);
+    } else {
+        char *base = SDL_GetPrefPath("", "");
+        if (!base) {
+            return false;
+        }
+
+        char *apath = NULL;
+        SDL_asprintf(&apath, "%s%s", base, path);
+        SDL_free(base);
+        if (!apath) {
+            return false;
+        }
+        rc = stat(apath, &statbuf);
+        SDL_free(apath);
+    }
 #else
     rc = stat(path, &statbuf);
 #endif

+ 33 - 1
src/io/SDL_iostream.c

@@ -957,6 +957,39 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
         }
     }
 
+#elif defined(SDL_PLATFORM_IOS)
+
+    // Try to open the file on the filesystem first
+    FILE *fp = NULL;
+    if (*file == '/') {
+        fp = fopen(file, mode);
+    } else {
+        // We can't write to the current directory, so use a writable path
+        char *base = SDL_GetPrefPath("", "");
+        if (!base) {
+            return NULL;
+        }
+
+        char *path = NULL;
+        SDL_asprintf(&path, "%s%s", base, file);
+        SDL_free(base);
+        if (!path) {
+            return NULL;
+        }
+
+        fp = fopen(path, mode);
+        SDL_free(path);
+    }
+
+    if (!fp) {
+        SDL_SetError("Couldn't open %s: %s", file, strerror(errno));
+    } else if (!IsRegularFileOrPipe(fp)) {
+        fclose(fp);
+        SDL_SetError("%s is not a regular file or pipe", file);
+    } else {
+        iostr = SDL_IOFromFP(fp, true);
+    }
+
 #elif defined(SDL_PLATFORM_WINDOWS)
     HANDLE handle = windows_file_open(file, mode);
     if (handle != INVALID_HANDLE_VALUE) {
@@ -975,7 +1008,6 @@ SDL_IOStream *SDL_IOFromFile(const char *file, const char *mode)
             SDL_SetError("Couldn't open %s: %s", file, strerror(errno));
         } else if (!IsRegularFileOrPipe(fp)) {
             fclose(fp);
-            fp = NULL;
             SDL_SetError("%s is not a regular file or pipe", file);
         } else {
             iostr = SDL_IOFromFP(fp, true);